通用应用程序:如何将 ListViewItem(容器)的 属性 绑定到实际项目(视图模型)?
Universal Apps: How to bind a property of a ListViewItem (container) to the actual item (View Model)?
我有这个ListView
<ListView ItemsSource="{Binding Items}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Background" Value="{Binding IsValid, Converter={StaticResource BooleanToBrushConverter}" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
我知道绑定不适用于通用应用程序中的设置器,但是,如何将项目的容器与项目本身绑定?如果您不能提供任何逻辑,只能提供常量值,那么创建自定义容器有什么意义?
您需要小心 UWP ListViewItem 中的背景,因为围绕它有很多复杂的主题,包括不同种类的按下和拖动背景
我认为实现此目的的更简单方法是更改 ListViewItem
中的内容对齐方式,然后将网格添加到您可以从中添加背景的项目模板
<ListView ItemsSource="{Binding Items}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Grid Background="{Binding Path=IsValid, Converter={StaticResource BooleanToBrushConverter}}">
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
这真的很简单。
I would guess you are trying to use the variable sized grid view? That's a pretty common request, actually. But what you are asking for is tricky because of the various scopes and how things are rendered.
您首先想到的是用您自己的自定义 ListView 覆盖 ListView。我们称它为 MyListView。像这样:
public class MyItem
{
public int RowSpan { get; set; }
public int ColSpan { get; set; }
}
public class MyListView : ListView
{
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
var model = item as MyItem;
try
{
element.SetValue(VariableSizedWrapGrid.ColumnSpanProperty, model.ColSpan);
element.SetValue(VariableSizedWrapGrid.RowSpanProperty, model.RowSpan);
}
catch
{
element.SetValue(VariableSizedWrapGrid.ColumnSpanProperty, 1);
element.SetValue(VariableSizedWrapGrid.RowSpanProperty, 1);
}
finally
{
element.SetValue(VerticalContentAlignmentProperty, VerticalAlignment.Stretch);
element.SetValue(HorizontalContentAlignmentProperty, HorizontalAlignment.Stretch);
base.PrepareContainerForItemOverride(element, item);
}
}
}
一切都发生在 PrepareContainerForItemOverride
中,这是您需要在子类中重写的唯一方法。另请注意,我没有将它们设置为绑定。这是因为只有在呈现项目时才会观察到这些属性。如果您想刷新您的 ListView 并根据新值重新呈现您的项目,您需要在根面板上调用 InvalidateMeasure()
,这很棘手。你可以这样做:
// MyListView
public void Update()
{
if (!(this.ItemsPanelRoot is VariableSizedWrapGrid))
throw new ArgumentException("ItemsPanel is not VariableSizedWrapGrid");
foreach (var container in this.ItemsPanelRoot.Children.Cast<GridViewItem>())
{
var model = item as MyItem;
VariableSizedWrapGrid.SetRowSpan(container, data.RowSpan);
VariableSizedWrapGrid.SetColumnSpan(container, data.ColSpan);
}
this.ItemsPanelRoot.InvalidateMeasure();
}
如果这有意义,您可以查看整个实现 here。
祝你好运!
好的,您无法使用常规方法绑定到 DataContext,但是您可以使用其他(智能)方法来完成:
参见 this post。它提供了一个 "helper" 允许使用 Setter.
绑定到 DataContext
我有这个ListView
<ListView ItemsSource="{Binding Items}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Background" Value="{Binding IsValid, Converter={StaticResource BooleanToBrushConverter}" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
我知道绑定不适用于通用应用程序中的设置器,但是,如何将项目的容器与项目本身绑定?如果您不能提供任何逻辑,只能提供常量值,那么创建自定义容器有什么意义?
您需要小心 UWP ListViewItem 中的背景,因为围绕它有很多复杂的主题,包括不同种类的按下和拖动背景
我认为实现此目的的更简单方法是更改 ListViewItem
中的内容对齐方式,然后将网格添加到您可以从中添加背景的项目模板
<ListView ItemsSource="{Binding Items}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Grid Background="{Binding Path=IsValid, Converter={StaticResource BooleanToBrushConverter}}">
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
这真的很简单。
I would guess you are trying to use the variable sized grid view? That's a pretty common request, actually. But what you are asking for is tricky because of the various scopes and how things are rendered.
您首先想到的是用您自己的自定义 ListView 覆盖 ListView。我们称它为 MyListView。像这样:
public class MyItem
{
public int RowSpan { get; set; }
public int ColSpan { get; set; }
}
public class MyListView : ListView
{
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
var model = item as MyItem;
try
{
element.SetValue(VariableSizedWrapGrid.ColumnSpanProperty, model.ColSpan);
element.SetValue(VariableSizedWrapGrid.RowSpanProperty, model.RowSpan);
}
catch
{
element.SetValue(VariableSizedWrapGrid.ColumnSpanProperty, 1);
element.SetValue(VariableSizedWrapGrid.RowSpanProperty, 1);
}
finally
{
element.SetValue(VerticalContentAlignmentProperty, VerticalAlignment.Stretch);
element.SetValue(HorizontalContentAlignmentProperty, HorizontalAlignment.Stretch);
base.PrepareContainerForItemOverride(element, item);
}
}
}
一切都发生在 PrepareContainerForItemOverride
中,这是您需要在子类中重写的唯一方法。另请注意,我没有将它们设置为绑定。这是因为只有在呈现项目时才会观察到这些属性。如果您想刷新您的 ListView 并根据新值重新呈现您的项目,您需要在根面板上调用 InvalidateMeasure()
,这很棘手。你可以这样做:
// MyListView
public void Update()
{
if (!(this.ItemsPanelRoot is VariableSizedWrapGrid))
throw new ArgumentException("ItemsPanel is not VariableSizedWrapGrid");
foreach (var container in this.ItemsPanelRoot.Children.Cast<GridViewItem>())
{
var model = item as MyItem;
VariableSizedWrapGrid.SetRowSpan(container, data.RowSpan);
VariableSizedWrapGrid.SetColumnSpan(container, data.ColSpan);
}
this.ItemsPanelRoot.InvalidateMeasure();
}
如果这有意义,您可以查看整个实现 here。
祝你好运!
好的,您无法使用常规方法绑定到 DataContext,但是您可以使用其他(智能)方法来完成:
参见 this post。它提供了一个 "helper" 允许使用 Setter.
绑定到 DataContext