我有wpf应用程序,数独游戏。我有一个游戏网格的模型和用户控件(9x9平方)。因为我对绑定的了解有限而且我没有足够的时间,所以我决定在没有数据绑定的情况下使其成为旧的方式,并且手动同步模型和视图。然而,这是非常不洁净和同步问题出现。
我决定转换为正确的数据绑定。
我认为我的网格应该像itemscontrol(listbox或combobox),但不是线性列表,而是将其项目布局为二维网格。
我是绑定新手,我不知道如何实现我的目标。我有模型类,它有一些关于当前拼图的一般信息,并包含单元格的集合。每个细胞都有自己的特性,如价值,可能性,状态等。
我可以控制每个单元格的整个网格和用户控制。我需要网格绑定到我的模型的一些属性(例如,禁用,启用,数独类型)和每个单元格绑定到我相应的单元格 - 值,背景等。
编辑:细胞处于可观察的集合中。每个单元格都有X和Y属性。我认为它们应该以某种方式绑定到Grid.Row和Grid.Column属性。
你能指点一下如何继续吗?特别是创建itemscontrol以及如何绑定它?
谢谢。
答案 0 :(得分:1)
1)是否可以观察到? - 不,你可以使用例如List<List<CellModel>>()
2)如果你仍想使用数组[,] - 如果你想使用ItemsControl
,你可能需要某种转换器
3)您可以使用ItemTemplate控制项目,也可以是项目控件
希望这会有所帮助
编辑1:让我们从第2点创建转换器......
public class ArrayConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var val = value as CellModel[,];
if (val == null) return null;
return ToEnumerable(val);
}
private IEnumerable<IEnumerable<CellModel>> ToEnumerable(CellModel[,] array)
{
var count = array.GetLength(0);
for (int i = 0; i < array.GetLength(0); ++i)
{
yield return GetLine(array, i);
}
}
private IEnumerable<CellModel> GetLine(CellModel[,] array, int line)
{
var count = array.GetLength(1);
for (int i = 0; i < count; ++i)
{
yield return array[line, i];
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
编辑2:你的xaml看起来像(见第3点):
<Grid>
<Grid.Resources>
<Converters:ArrayConverter x:Key="ArrayConverter"/>
</Grid.Resources>
<ItemsControl
ItemsSource="{Binding CellArray, Mode=OneWay, Converter={StaticResource ArrayConverter}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl
ItemsSource="{Binding ., Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- TODO: Add cell template here -->
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
编辑3:添加了行<StackPanel Orientation="Horizontal" IsItemsHost="True"/>
- 这将使您的线条呈现为水平
编辑4:您的视图模型现在可能是这样的:
public class GameViewModel : ViewModelBase
{
public void Load()
{
var array = new CellModel[9, 9];
for (int i = 0; i < 9; ++i)
{
for (int j = 0; j < 9; ++j)
{
array[i, j] = new CellModel()
{
//TODO: init properties of the cell[i, j]
};
}
}
this.CellArray = array;
}
CellModel[,] _CellArray;
public CellModel[,] CellArray
{
get
{
return _CellArray;
}
private set
{
if (_CellArray == value) return;
_CellArray = value;
NotifyPropertyChanged("CellArray");
}
}
}
如果有些事情仍不清楚,请告诉我
编辑5:取决于您的上次编辑,让我们更改我们的XAML:
<ItemsControl
ItemsSource="{Binding CellArray, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid
Grid.Column="{Binding X}"
Grid.Row="{Binding Y}">
<!-- TODO: -->
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid IsItemsHost="True">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
答案 1 :(得分:0)
您不需要使用ObservableCollection
绑定到集合,但是如果您希望自动实现CollectionChange通知,则建议使用它。
这意味着如果您更新集合(例如,清除它并开始新游戏),它将自动告知UI集合已更改,UI将使用新元素重绘自己。
您还可以使用ObservableCollections
的Linq语句查找特定元素。例如,以下内容将返回与指定条件匹配的第一个单元格,如果未找到任何项目,则返回null
var cell = MyCollection.FirstOrDefault(
cell => cell.Y == desiredRowIndex && cell.X == desiredColumnIndex);