1

我目前正在创建一个 connect-4 游戏以学习 WPF 和 XAML。我制作了 UI,但我遇到了一个问题。

您可以在下面看到有关游戏板的 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 数组(一个 Empty、Red 和 Yellow 的枚举)中。

椭圆的颜色是使用 SolidBrushColor 类提供的。

我的问题是我不知道如何根据游戏模型更改椭圆的颜色。

我想我应该使用数据绑定,但我必须在绑定数据之前将颜色从 Token 类型转换为 SolidBrushColor 类型。我认为它可以使用一些 DataObjectProvider 对象来实现,但是为这样一个简单的任务创建 42 个 DataObjectProvider 对象似乎过于复杂......

那么根据最佳实践,正确的解决方案是什么?

4

3 回答 3

3

您需要在后端使用某种 ViewModel,然后利用 DataBinding。

假设以下(人为的)ViewModel 结构表示一个四连接板。

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 来表示您的板。

主窗口.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>

需要注意的重要事项是:

  • 基于 Square 的 Token 属性值设置椭圆颜色的 DataTrigger。
  • 使用带有 UniformGrid 支持的 ItemsPanel。
  • SquareViewModel 中 INotifyPropertyChanged 的​​实现,这样当 Token 的值发生变化时,View 就代表了这一点。
  • d:DataContext 属性的使用,它将表单的设计时 DataContext 设置为 BoardViewModel 的实例(将自身初始化为随机标记)。

在运行时,您需要将板视图的 DataContext 设置为 BoardViewModel 的真实实例(或任何您的 ViewModel 被调用),但如何更改标记颜色的基本概念已经存在。

于 2014-01-08T03:11:21.653 回答
1

如果Token是具有颜色枚举属性的类,则可以在Token类中添加另一个字符串类型的属性。在属性的getter中根据颜色枚举属性返回一个有效的颜色名称字符串。这样您就可以将每个Ellipse's Fill属性绑定到相应Token的颜色字符串属性,而无需构建您自己的转换器。WPF 已经内置了字符串到颜色的转换器,这就是为什么您可以在 XAML 中指定颜色字符串并在渲染时获得正确的颜色画笔。

<Ellipse Grid.Row="0" Grid.Column="0" Margin="8"
         Fill="{Binding TokenList[0].ColorStringProperty}" />

请注意,上述解决方案是一种更好的做法,然后Ellipse在 XAML 中为每个名称分配名称,然后从代码中更改颜色。它适用于您现有的代码,无需彻底修改。但最佳实践将指导您在更大程度上利用数据绑定(如@Iain 的回答中所指出的),并实现 MVVM 设计模式。更长的路要走,但你会发现它值得付出努力。

最后,您还需要在类或任何其他将 UI 绑定到类对象属性的类中实现INotifyPropertyChanged (您还可以在@Heena 的答案中看到一个示例)。TokenINotifyPropertyChanged

于 2014-01-08T02:47:59.137 回答
0

是的,您应该使用数据绑定。您应该将Fill颜色绑定到模型并使用 aValueConverter在枚举和颜色之间进行转换。或者,在您的 ViewModel 上有一个 Color 属性并直接绑定到该属性。

我认为使用 aGrid是错误的方法,您应该将您的板建模为列表令牌(实际上是列表列表,用于行和列),然后使用ItemsControl带有 aItemsTemplate来创建板。这意味着 XAML 的重复性要少得多。

当您尝试学习 WPF 和 XAML 时,请尝试使用谷歌搜索上面的内容,看看您能走多远。

于 2014-01-08T01:51:03.260 回答