如果我使用 DataTemplateSelector,在哪里设置自定义单元格与客户渲染器的绑定?
Where to set bindings for a custom cell with customer renderer if I am using a DataTemplateSelector?
我有一个 DataTemplateSelector 可以在两个不同的单元格之间进行选择。在 Android,此模板选取定义为 Android xml 文件的单元格。我可以确认模板选择器正在工作,因为我显示了两个不同的色圈,而且颜色是正确的。但是我的数据没有被绑定,我不确定为什么。我想我没有在某处设置绑定,但我不确定 where/how 这样做。
这是我的页面,其中包含带有 DataTemplateSelector 的 ListView。我在这里设置了 ItemsSource,但我从未为列表项的不同部分设置绑定。这就是我不知道该怎么做的地方。
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.Pages.Routines.TopLevelRoutinesPage"
xmlns:statics="clr-namespace:MyApp.Statics;assembly=MyApp"
xmlns:controls="clr-namespace:MyApp.Controls;assembly=MyApp">
<ContentPage.Resources>
<ResourceDictionary>
<controls:RoutinesDataTemplateSelector x:Key="RoutinesDataTemplateSelector"></controls:RoutinesDataTemplateSelector>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
Orientation="Vertical"
Spacing="0">
<ListView ItemsSource="{Binding SelectedRoutineTree}"
ItemTemplate="{StaticResource RoutinesDataTemplateSelector}"
x:Name="RoutinesView"
ItemSelected="RoutineClicked"
Margin ="0, 8, 0, 0">
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
隐藏代码:
using MyApp.ViewModels;
using MyCloudContracts.DTOs;
using System;
using System.Linq;
using Xamarin.Forms;
namespace MyApp.Pages.Routines
{
public partial class TopLevelRoutinesPage : ContentPage
{
private TopLevelRoutinesViewModel _viewModel;
private string _projCompName;
public TopLevelRoutinesPage(Guid docId, bool fromCompany, string projCompName)
{
InitializeComponent();
_projCompName = projCompName;
Title = _projCompName;
_viewModel = new TopLevelRoutinesViewModel(docId, fromCompany);
BindingContext = _viewModel;
if (Device.OS == TargetPlatform.Android)
RoutinesView.SeparatorVisibility = SeparatorVisibility.None;
}
private async void RoutineClicked(object sender, SelectedItemChangedEventArgs e)
{
//since this is also called when an item is deselected, return if set to null
if (e.SelectedItem == null)
return;
var selectedRoutine = (PublishedDocumentFragmentDTO)e.SelectedItem;
var fragId = selectedRoutine.FragmentId;
var title = selectedRoutine.Title;
var blobIdStr = selectedRoutine.BlobId;
var blobId = new Guid(blobIdStr);
if (selectedRoutine.Children.Any())
{
var routineTree = _viewModel.SelectedRoutineTree;
var subroutinesPage = new SubroutinesPage(routineTree, fragId, title, blobId, _projCompName);
await Navigation.PushAsync(subroutinesPage);
}
else
{
var routinePage = new RoutinePage(title, blobId);
await Navigation.PushAsync(routinePage);
}
//take away selected background
((ListView)sender).SelectedItem = null;
}
}
}
DataTemplateSelector
using MyApp.Pages.Routines.CustomCells;
using MyCloudContracts.DTOs;
using Xamarin.Forms;
namespace MyApp.Controls
{
class RoutinesDataTemplateSelector : DataTemplateSelector
{
private readonly DataTemplate _folderDataTemplate;
private readonly DataTemplate _routineDataTemplate;
public RoutinesDataTemplateSelector()
{
_folderDataTemplate = new DataTemplate(typeof(FolderViewCell));
_routineDataTemplate = new DataTemplate(typeof(RoutineViewCell));
}
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
var chooser = item as PublishedDocumentFragmentDTO;
if (chooser == null)
return null;
else if (chooser.Children.Length == 0)
{
return _routineDataTemplate;
}
else
{
return _folderDataTemplate;
}
}
}
}
以及我的自定义 ViewCell 之一的示例。我认为这是我错的地方,但我不确定为什么。我制作了属性,但我不知道如何正确设置它们。
using Xamarin.Forms;
namespace MyApp.Pages.Routines.CustomCells
{
public class RoutineViewCell : ViewCell
{
public static readonly BindableProperty TitleProperty =
BindableProperty.Create("Title", typeof(string), typeof(RoutineViewCell), "");
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
}
}
感谢您的帮助:)
我找到了答案。我需要覆盖自定义单元格文件中的 OnBindingContextChanged()
。我的工作代码现在看起来像这样:
using Xamarin.Forms;
namespace MyApp.Pages.Routines.CustomCells
{
public class RoutineViewCell : ViewCell
{
public static readonly BindableProperty TitleProperty =
BindableProperty.Create("Title", typeof(string), typeof(RoutineViewCell), "");
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
protected override void OnBindingContextChanged()
{
this.SetBinding(TitleProperty, "Title");
base.OnBindingContextChanged();
}
}
}
我有一个 DataTemplateSelector 可以在两个不同的单元格之间进行选择。在 Android,此模板选取定义为 Android xml 文件的单元格。我可以确认模板选择器正在工作,因为我显示了两个不同的色圈,而且颜色是正确的。但是我的数据没有被绑定,我不确定为什么。我想我没有在某处设置绑定,但我不确定 where/how 这样做。
这是我的页面,其中包含带有 DataTemplateSelector 的 ListView。我在这里设置了 ItemsSource,但我从未为列表项的不同部分设置绑定。这就是我不知道该怎么做的地方。
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.Pages.Routines.TopLevelRoutinesPage"
xmlns:statics="clr-namespace:MyApp.Statics;assembly=MyApp"
xmlns:controls="clr-namespace:MyApp.Controls;assembly=MyApp">
<ContentPage.Resources>
<ResourceDictionary>
<controls:RoutinesDataTemplateSelector x:Key="RoutinesDataTemplateSelector"></controls:RoutinesDataTemplateSelector>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
Orientation="Vertical"
Spacing="0">
<ListView ItemsSource="{Binding SelectedRoutineTree}"
ItemTemplate="{StaticResource RoutinesDataTemplateSelector}"
x:Name="RoutinesView"
ItemSelected="RoutineClicked"
Margin ="0, 8, 0, 0">
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
隐藏代码:
using MyApp.ViewModels;
using MyCloudContracts.DTOs;
using System;
using System.Linq;
using Xamarin.Forms;
namespace MyApp.Pages.Routines
{
public partial class TopLevelRoutinesPage : ContentPage
{
private TopLevelRoutinesViewModel _viewModel;
private string _projCompName;
public TopLevelRoutinesPage(Guid docId, bool fromCompany, string projCompName)
{
InitializeComponent();
_projCompName = projCompName;
Title = _projCompName;
_viewModel = new TopLevelRoutinesViewModel(docId, fromCompany);
BindingContext = _viewModel;
if (Device.OS == TargetPlatform.Android)
RoutinesView.SeparatorVisibility = SeparatorVisibility.None;
}
private async void RoutineClicked(object sender, SelectedItemChangedEventArgs e)
{
//since this is also called when an item is deselected, return if set to null
if (e.SelectedItem == null)
return;
var selectedRoutine = (PublishedDocumentFragmentDTO)e.SelectedItem;
var fragId = selectedRoutine.FragmentId;
var title = selectedRoutine.Title;
var blobIdStr = selectedRoutine.BlobId;
var blobId = new Guid(blobIdStr);
if (selectedRoutine.Children.Any())
{
var routineTree = _viewModel.SelectedRoutineTree;
var subroutinesPage = new SubroutinesPage(routineTree, fragId, title, blobId, _projCompName);
await Navigation.PushAsync(subroutinesPage);
}
else
{
var routinePage = new RoutinePage(title, blobId);
await Navigation.PushAsync(routinePage);
}
//take away selected background
((ListView)sender).SelectedItem = null;
}
}
}
DataTemplateSelector
using MyApp.Pages.Routines.CustomCells;
using MyCloudContracts.DTOs;
using Xamarin.Forms;
namespace MyApp.Controls
{
class RoutinesDataTemplateSelector : DataTemplateSelector
{
private readonly DataTemplate _folderDataTemplate;
private readonly DataTemplate _routineDataTemplate;
public RoutinesDataTemplateSelector()
{
_folderDataTemplate = new DataTemplate(typeof(FolderViewCell));
_routineDataTemplate = new DataTemplate(typeof(RoutineViewCell));
}
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
var chooser = item as PublishedDocumentFragmentDTO;
if (chooser == null)
return null;
else if (chooser.Children.Length == 0)
{
return _routineDataTemplate;
}
else
{
return _folderDataTemplate;
}
}
}
}
以及我的自定义 ViewCell 之一的示例。我认为这是我错的地方,但我不确定为什么。我制作了属性,但我不知道如何正确设置它们。
using Xamarin.Forms;
namespace MyApp.Pages.Routines.CustomCells
{
public class RoutineViewCell : ViewCell
{
public static readonly BindableProperty TitleProperty =
BindableProperty.Create("Title", typeof(string), typeof(RoutineViewCell), "");
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
}
}
感谢您的帮助:)
我找到了答案。我需要覆盖自定义单元格文件中的 OnBindingContextChanged()
。我的工作代码现在看起来像这样:
using Xamarin.Forms;
namespace MyApp.Pages.Routines.CustomCells
{
public class RoutineViewCell : ViewCell
{
public static readonly BindableProperty TitleProperty =
BindableProperty.Create("Title", typeof(string), typeof(RoutineViewCell), "");
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
protected override void OnBindingContextChanged()
{
this.SetBinding(TitleProperty, "Title");
base.OnBindingContextChanged();
}
}
}