我目前正在创建一个connect-4游戏,以便学习WPF& XAML。我制作了用户界面,但我遇到了问题。
您可以在下面看到有关游戏主板的XAML代码摘录:
<Grid DockPanel.Dock="Bottom" Background="#FF1506A4" MouseLeftButtonUp="Grid_MouseLeftButtonUp_1">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
... 5 more rows
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
... 6 more columns
</Grid.ColumnDefinitions>
<Ellipse Grid.Row="0" Grid.Column="0" Fill="White" Margin="8"/>
... 41 more ellipses
</Grid>
该棋盘存储在GameState类中的Token(带有空,红色和黄色的枚举)数组中。
使用SolidBrushColor类提供椭圆的颜色。
我的问题是我不知道如何根据游戏模型改变椭圆的颜色。
我想我应该使用数据绑定,但是我必须在绑定数据之前将颜色从Token类型转换为SolidBrushColor类型。我认为可以使用一些DataObjectProvider对象来实现,但是为这样一个简单的任务创建42个DataObjectProvider对象似乎过于复杂......
那么根据最佳实践,什么是正确的解决方案?
答案 0 :(得分:3)
您需要在后端使用某种ViewModel,然后利用DataBinding。
假设以下(人为的)ViewModel结构代表Connect Four板。
<强> BoardViewModel.cs 强>
public class BoardViewModel
{
public BoardViewModel()
{
var rand = new Random();
Squares = Enumerable
.Range(1, 42)
.Select(a => new SquareViewModel() { Token = rand.Next(-1, 2) })
.ToList();
}
public List<SquareViewModel> Squares { get; set; }
}
<强> SquareViewModel.cs 强>
public class SquareViewModel : INotifyPropertyChanged
{
private int _Token;
public int Token
{
get
{
return _Token;
}
set
{
if (_Token.Equals(value)) return;
_Token = value;
RaisePropertyChanged("Token");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
var handlers = PropertyChanged;
if (handlers != null)
{
var args = new PropertyChangedEventArgs(property);
handlers(this, args);
}
}
}
然后您可以使用以下XAML代表您的电路板。
<强> MainWindow.xaml 强>
<Window
x:Class="ConnectFour.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
xmlns:ConnectFour="clr-namespace:ConnectFour"
Title="MainWindow" Height="350" Width="525"
d:DataContext="{d:DesignInstance Type={x:Type ConnectFour:BoardViewModel}, IsDesignTimeCreatable=True}">
<ItemsControl
ItemsSource="{Binding Squares}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse
Stroke="Magenta">
<Ellipse.Style>
<Style TargetType="Ellipse">
<Style.Triggers>
<DataTrigger Binding="{Binding Token}" Value="0">
<Setter Property="Fill" Value="Black" />
</DataTrigger>
<DataTrigger Binding="{Binding Token}" Value="1">
<Setter Property="Fill" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid IsItemsHost="True" Columns="6" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Window>
需要注意的重要事项是:
在运行时,您需要将Board View的DataContext设置为BoardViewModel的实际实例(或者调用ViewModel的任何实例),但是存在如何更改标记颜色的基本思路
答案 1 :(得分:1)
如果Token
是具有颜色枚举属性的类,则可以在Token
类中添加另一个string类型的属性。在属性的getter中,根据color enum属性返回有效的颜色名称字符串。这样,您可以将每个Ellipse's Fill
属性绑定到相应的Token
的颜色字符串属性,而无需构建自己的转换器。 WPF已经内置了一个字符串到颜色转换器,这就是为什么你可以在XAML中指定颜色字符串并在渲染时获得正确的颜色画笔。
<Ellipse Grid.Row="0" Grid.Column="0" Margin="8"
Fill="{Binding TokenList[0].ColorStringProperty}" />
请注意,上述解决方案是一种更好的做法,然后在XAML中为每个Ellipse
分配名称,然后从代码中更改颜色。并且它适用于您现有的代码而无需根本修改。但最佳实践将指导您更多地利用数据绑定(如@ Iain的答案中所示),并实现MVVM设计模式。更长的路要走,但你会觉得值得努力。
最后,您还需要在Token
类或任何其他具有绑定到类对象属性的UI的类中实现INotifyPropertyChanged(您还可以在{{1}上看到示例在@ Heena的回答中)。
答案 2 :(得分:0)
是的,你应该使用数据绑定。您应该将Fill
颜色绑定到模型,并使用ValueConverter
在枚举和颜色之间进行转换。或者在ViewModel上有一个Color属性并直接绑定它。
我认为使用Grid
是错误的方法,您应该将您的电路板建模为列表标记(实际上是列表列表,行和列),然后使用ItemsControl
一个ItemsTemplate
来创建董事会。这意味着重复性更低的XAML。
当您尝试学习WPF和XAML时,请尝试使用Google搜索上面的内容,看看您能获得多远。