WPF XAML使用数据绑定更改多个椭圆颜色

时间:2014-01-07 23:47:10

标签: c# wpf xaml xaml-binding

我目前正在创建一个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对象似乎过于复杂......

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

3 个答案:

答案 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>

需要注意的重要事项是:

  • DataTriggers,根据Square的Token属性值设置Ellipses的颜色。
  • 使用带有UniformGrid备份的ItemsPanel。
  • 在SquareViewModel中实现INotifyPropertyChanged,以便当Token的值更改时,View代表该值。
  • d:DataContext属性的用法,该属性将表单的设计时DataSetext设置为BoardViewModel的实例(将其自身初始化为随机令牌)。

在运行时,您需要将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搜索上面的内容,看看您能获得多远。