如何在 <ViewCell> C# 中添加带有 a 到<Grid>表视图



>我正在构造一个动态的TableView。到目前为止,我有这个:

var section = new TableSection("Available Categories");
foreach (var category in categoryGroups)
{
var name = (string)category.Name;
var cell = new TextCell { Text = name };
section.Add(cell);
}
tableView.Root.Add(section);

这有效,但我想使用与当前在 XAML 中相同的网格的 ViewCell,而不是使用文本单元格:

< ViewCell >
< Grid VerticalOptions = "CenterAndExpand" Padding = "20, 0" >
< Grid.ColumnDefinitions >
< ColumnDefinition Width = "*" />
< ColumnDefinition Width = "Auto" />
< ColumnDefinition Width = "20" />
</ Grid.ColumnDefinitions >
< Label Style = "{DynamicResource ListItemTextStyle}" Grid.Column = "0" HorizontalOptions = "StartAndExpand" Text = "{Binding Name}" />
< Label Style = "{DynamicResource ListItemTextStyle}" Grid.Column = "1" HorizontalOptions = "End" XAlign = "End" Text = "{Binding TotalWordCount}" VerticalOptions = "Center" TextColor = "Gray" />
< Label Grid.Column = "2" Text = "{x:Static local:FontAwesome.FACheck}" HorizontalTextAlignment = "End" HorizontalOptions = "End" FontFamily = "FontAwesome" XAlign = "Center" FontSize = "13" IsVisible = "{Binding IsToggled}" TextColor = "#1E90FF" />
</ Grid >
</ ViewCell >

任何人都可以给我关于如何将其添加到我的 C# 代码的建议。我只知道如何在 XAML 中做到这一点。

注意

以下是我了解动态样式的地方:

https://developer.xamarin.com/guides/xamarin-forms/user-interface/styles/device/

选项 1:在 C# 中定义自定义 ViewCell

下面是你共享的 XAML 模板的 C# 等效项:

public class CustomViewCell : ViewCell
{
public CustomViewCell()
{
var label1 = new Label
{
HorizontalOptions = LayoutOptions.StartAndExpand
};
//or, label1.Style = Device.Styles.ListItemTextStyle;
label1.SetDynamicResource(VisualElement.StyleProperty, "ListItemTextStyle");
Grid.SetColumn(label1, 0);
label1.SetBinding(Label.TextProperty, "Name");
var label2 = new Label
{
HorizontalOptions = LayoutOptions.End,
//XAlign = TextAlignment.End, //not needed
VerticalOptions = LayoutOptions.Center,
TextColor = Color.Gray
};
//or, label2.Style = Device.Styles.ListItemTextStyle;
label2.SetDynamicResource(VisualElement.StyleProperty, "ListItemTextStyle");
Grid.SetColumn(label2, 1);
label2.SetBinding(Label.TextProperty, "TotalWordCount");
var label3 = new Label
{
HorizontalOptions = LayoutOptions.End,
HorizontalTextAlignment = TextAlignment.End,
VerticalOptions = LayoutOptions.Center,
//XAlign = TextAlignment.Start, //not needed
FontFamily = "FontAwesome",
FontSize = 13,
TextColor = Color.FromHex("#1E90FF"),
Text = FontAwesome.FACheck,
};
Grid.SetColumn(label3, 2);
label3.SetBinding(VisualElement.IsVisibleProperty, "IsToggled");
var grid = new Grid
{
VerticalOptions = LayoutOptions.CenterAndExpand,
Padding = new Thickness(20, 0),
ColumnDefinitions = new ColumnDefinitionCollection()
{
new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) },
new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) },
new ColumnDefinition() { Width = new GridLength(20) },
},
Children = {
label1,
label2,
label3
}
};
View = grid;
}
}

选项 2:在 XAML 中定义自定义视图单元格

即使动态创建TableView仍可以使用基于 XAML 的方法。只需创建一个新的 XAML 控件,如下所示:

示例视图单元格 XAML

<ViewCell 
xmlns="http://xamarin.com/schemas/2014/forms" 
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
x:Class="AppNamespace.MyViewCell">
<Grid VerticalOptions="CenterAndExpand" Padding = "20, 0" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="75" />
</Grid.ColumnDefinitions>
<Label Grid.Column = "0" HorizontalOptions = "StartAndExpand" Text = "{Binding Name}" />
<Label Grid.Column = "1" HorizontalOptions = "End" XAlign = "End" Text = "{Binding TotalWordCount}" VerticalOptions = "Center" TextColor = "Gray" />
<Switch Grid.Column = "2" HorizontalOptions = "End"  IsToggled = "{Binding IsToggled}"  />
</Grid>
</ViewCell>

代码隐藏

public partial class MyViewCell : ViewCell
{
public MyViewCell()
{
InitializeComponent();
}
}

您可以按如下方式创建TableView

var section = new TableSection("Available Categories");
foreach (var category in categoryGroups)
{
var cell = new MyViewCell { BindingContext = category };
section.Add(cell);
}
tableView.Root.Add(section);

选项 3.使用ItemSource支持(如ListView(创建自己的自定义TableView

public class DynamicTableView : TableView
{
/// <summary>
/// Bindable property for the data source
/// </summary>
public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create(
"ItemsSource", typeof(IDictionary), typeof(DynamicTableView), propertyChanging: OnItemsSourceChanged);
/// <summary>
/// Gets or sets the items source - can be any collection of elements.
/// </summary>
/// <value>The items source.</value>
public IDictionary ItemsSource
{
get { return (IDictionary)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
/// <summary>
/// Bindable property for the data template to visually represent each item.
/// </summary>
public static readonly BindableProperty ItemTemplateProperty = BindableProperty.Create(
"ItemTemplate", typeof(DataTemplate), typeof(DynamicTableView));
/// <summary>
/// Gets or sets the item template used to generate the visuals for a single item.
/// </summary>
/// <value>The item template.</value>
public DataTemplate ItemTemplate
{
get { return (DataTemplate)GetValue(ItemTemplateProperty); }
set { SetValue(ItemTemplateProperty, value); }
}
/// <summary>
/// Initializes an ItemsControl.
/// </summary>
public DynamicTableView()
{
}
/// <summary>
/// This is called when the underlying data source is changed.
/// </summary>
/// <param name="bindable">ItemsSource</param>
/// <param name="oldValue">Old value.</param>
/// <param name="newValue">New value.</param>
static void OnItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
{
((DynamicTableView)bindable).OnItemsSourceChangedImpl((IDictionary)oldValue, (IDictionary)newValue);
}
/// <summary>
/// Instance method called when the underlying data source is changed through the
/// <see cref="ItemsSource"/> property. This re-generates the list based on the 
/// new collection.
/// </summary>
/// <param name="oldValue">Old value.</param>
/// <param name="newValue">New value.</param>
void OnItemsSourceChangedImpl(IDictionary oldValue, IDictionary newValue)
{
Root.Clear();
if(newValue != null)
{
FillContainer(newValue);
}
}
/// <summary>
/// This method takes our items source and generates visuals for
/// each item in the collection; it can reuse visuals which were created
/// previously and simply changes the binding context.
/// </summary>
/// <param name="newValue">New items to display</param>
void FillContainer(IDictionary newValue)
{
Root.Clear();
var template = ItemTemplate;
foreach(var key in newValue.Keys)
{
var tableSection = new TableSection() { Title = key.ToString() };
var innerList = newValue[key] as IList;
if (innerList == null)
innerList = Enumerable.Repeat(newValue[key], 1).ToList();
foreach(var dataItem in innerList)
{
if (template != null)
{
var view = InflateTemplate(template, dataItem);
if (view != null)
tableSection.Add(view);
}
else
{
var label = new TextCell { Text = dataItem.ToString() };
tableSection.Add(label);
}
}
Root.Add(tableSection);
}
}
/// <summary>
/// Inflates the visuals for a data template or template selector
/// and adds it to our StackLayout.
/// </summary>
/// <param name="template">Template.</param>
/// <param name="item">Item.</param>
ViewCell InflateTemplate(DataTemplate template, object item)
{
// Pull real template from selector if necessary.
var dSelector = template as DataTemplateSelector;
if (dSelector != null)
template = dSelector.SelectTemplate(item, this);
var view = template.CreateContent() as ViewCell;
if (view != null)
{
view.BindingContext = item;
return view;
}
return null;
}
}

用法将如下所示:

<local:DynamicTableView ItemsSource="{Binding AllCategories}">
<local:DynamicTableView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid VerticalOptions="CenterAndExpand" Padding = "20, 0" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="75" />
</Grid.ColumnDefinitions>
<Label Grid.Column = "0" HorizontalOptions = "StartAndExpand" Text = "{Binding Name}" />
<Label Grid.Column = "1" HorizontalOptions = "End" XAlign = "End" Text = "{Binding TotalWordCount}" VerticalOptions = "Center" TextColor = "Gray" />
<Switch Grid.Column = "2" HorizontalOptions = "End"  IsToggled = "{Binding IsToggled}"  />
</Grid>
</ViewCell>
</DataTemplate>
</local:DynamicTableView.ItemTemplate>
</local:DynamicTableView>

和示例数据集:

public class SettingsViewModel {
public Categories AllCategories => new Categories();
}
public class Category {
public string Name { get; set; }
public int TotalWordCount { get; set; }
public bool IsToggled { get; set; }
}
public class Categories : Dictionary<string, List<Category>>
{
public Categories()
{
this.Add("Available Categories", new List<Category>(new []{
new Category(){ Name = "Test1", TotalWordCount = 10, IsToggled = true },
new Category(){ Name = "Test2", TotalWordCount = 25, IsToggled = true },
new Category(){ Name = "Test3", TotalWordCount = 20, IsToggled = false }
}));
this.Add("Other Categories", new List<Category>(new[]{
new Category(){ Name = "Test-N1", TotalWordCount = 30, IsToggled = true },
new Category(){ Name = "Test-N2", TotalWordCount = 50, IsToggled = false }
}));
}
}

基于旧问题的旧答案(不再有效(

如果您只需要为特定平台指定BackgroundColorFontSize- 您可以使用OnPlatform来执行此操作 - 则不需要自定义渲染器。

<ListView.Header>
<!-- don't forget to override spacing and padding properties to avoid default spacing -->
<StackLayout Spacing="0" Padding="0" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<StackLayout.BackgroundColor>
<OnPlatform x:TypeArguments="Color"
Android=""
WinPhone=""                                         
iOS="#000000">
</StackLayout.BackgroundColor>
<StackLayout Padding="10,35,10,10" Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<local:ExtLabel ExtStyleId="Body" Text="Custom body Label"></local:ExtLabel>
<local:ExtLabel ExtStyleId="Header" Text="Custom hdr Label"></local:ExtLabel>
</StackLayout>
</StackLayout>
</ListView.Header>

此外,在引用 listview 和渲染器的源代码时,特别是在这里 - 看起来标头/标头模板属性只是用作ListView中一组控件的占位符。如果在标头中提供自定义控件,框架将实例化并为其使用呈现器。

因此,如果您确实需要基于自定义渲染器的方法,那么您可以创建自定义控件,(例如CustomListViewHeader(;并为其实现一个 iOS 渲染器。

然后,可以在ListView标头或标头模板中使用此控件。

<ListView.Header>
<local:CustomListViewHeader />
</ListView.Header>

最新更新