WPF ItemsControl联合UniformGrid绑定集合,动态修改数据模板
例如:
扫雷程序:在第一次绑定数据模板后,后面要根据翻开的格子的属性,进行判断,来决定翻开后要展示插旗、空白格或者数字格
绑定数据的实体类
这里必须要把需要动态绑定的属性加上OnPropertyChanged事件,否则无法触发
public class NumData : INotifyPropertyChanged
{
private bool _isLei;
private bool _isOpen;
private bool _isSign;
public int Num { get; set; }
public bool IsLei
{
get { return _isLei; }
set { _isLei = value; OnPropertyChanged(nameof(IsLei)); }
}
public int Row { get; set; }
public int Col { get; set; }
public bool IsOpen
{
get { return _isOpen; }
set { _isOpen = value; OnPropertyChanged(nameof(IsOpen)); }
}
public bool IsSign
{
get { return _isSign; }
set { _isSign = value;OnPropertyChanged(nameof(IsSign)); }
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
窗体设置上下文,并设置响应式集合数据
public partial class GamePage : UserControl, INotifyPropertyChanged
{
public GamePage()
{
InitializeComponent();
}
public GamePage(int sizeRow, int sizeCol, int boomNum)
{
InitializeComponent();
SizeRow = sizeRow;
SizeCol = sizeCol;
DataContext = this; // 设置上下文
GenerateData(); // 生成初始数据
}
private bool GenerateData()
{
try
{
// 生成数据的逻辑
NumDatas = new List<NumDatas>();
return true;
}
catch (Exception)
{
return false;
}
}
#region 响应式数据定义
private List<NumData> _numDatas;
public List<NumData> NumDatas
{
get { return _numDatas; }
set
{
_numDatas = value;
OnPropertyChanged(nameof(NumDatas));
}
}
private int _sizeRow;
public int SizeRow
{
get { return _sizeRow; }
set
{
_sizeRow = value;
OnPropertyChanged(nameof(SizeRow));
}
}
private int _sizeCol;
public int SizeCol
{
get { return _sizeCol; }
set
{
_sizeCol = value;
OnPropertyChanged(nameof(SizeCol));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
创建数据模板
我这里是子窗体,所以是UserControl.Resources
创建了3个数据模板,并且声明了一个数据模板选择器
<UserControl.Resources>
<DataTemplate x:Key="TemplateA">
<TextBox Content={Binding Num}/>
</DataTemplate>
<DataTemplate x:Key="TemplateB">
<Border BorderThickness="1" BorderBrush="DarkGray">
<Button Background="#f7d3ba"></Button>
</Border>
</DataTemplate>
<DataTemplate x:Key="TemplateC">
<Border BorderThickness="1" BorderBrush="DarkGray"/>
</DataTemplate>
<!-- 定义 TemplateSelector -->
<local:ItemTemplateSelector x:Key="ItemTemplateSelector"
TemplateA="{StaticResource TemplateA}"
TemplateB="{StaticResource TemplateB}"
TemplateC="{StaticResource TemplateC}"/>
</UserControl.Resources>
下面介绍两种可以在运行中动态修改数据模版的方法
一、使用DataTrigger
MultiDataTrigger可以多条件选择,与DataTrigger作用是一样的
使用这种方法时,不需要声明上面的模板选择器ItemTemplateSelector
编辑XAML
<Grid>
<ItemsControl ItemsSource="{Binding NumDatas, Mode=TwoWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="{Binding SizeRow}" Columns="{Binding SizeCol}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<!--默认的模板-->
<ContentControl x:Name="cc" Content="{Binding}" ContentTemplate="{StaticResource TemplateA}"/>
<DataTemplate.Triggers>
<!--条件1:IsSign为True-->
<DataTrigger Binding="{Binding IsSign}" Value="True">
<Setter TargetName="cc" Property="ContentTemplate" Value="{StaticResource TemplateB}"/>
</DataTrigger>
<!--条件2:当IsLei为True,且IsOpen为True-->
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsLei}" Value="True"/>
<Condition Binding="{Binding IsOpen}" Value="True"/>
</MultiDataTrigger.Conditions>
<Setter TargetName="cc" Property="ContentTemplate" Value="{StaticResource TemplateC}"/>
</MultiDataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
二、使用DataTemplateSelector
创建模板选择器
public class ItemTemplateSelector : DataTemplateSelector
{
public DataTemplate TemplateA { get; set; }
public DataTemplate TemplateB { get; set; }
public DataTemplate TemplateC { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item is NumData numData)
{
PropertyChangedEventHandler lamda = null;
lamda = (o, args) =>
{
if(args.PropertyName == "IsSign" || args.PropertyName == "IsOpen")
{
numData.PropertyChanged -= lamda;
var cp = (ContentPresenter)container;
cp.ContentTemplateSelector = null;
cp.ContentTemplateSelector = this;
}
};
numData.PropertyChanged += lamda;
if (numData.IsSign)
{
return TemplateB;
}
else if (numData.IsLei && numData.IsOpen)
{
return TemplateC;
}
else
{
return TemplateA;
}
}
return base.SelectTemplate(item, container);
}
}
绑定模板选择器
对应上面创建数据模板里面的选择器
<Grid>
<ItemsControl ItemsSource="{Binding NumDatas, Mode=TwoWay}"
ItemTemplateSelector="{StaticResource ItemTemplateSelector}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="{Binding SizeRow}" Columns="{Binding SizeCol}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
使用这两种方法,都在程序运行的时候,修改集合对象属性值之后,动态更换数据模板

浙公网安备 33010602011771号