2014-01-07 72 views
1

我目前爲了學習WPF XAML &創建一個連接-4的比賽。我製作了UI,但是我遇到了一個問題。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> 

板被存儲在令牌中的類(空,紅色和黃色的枚舉)的數組遊戲狀態。使用類SolidBrushColor提供

橢圓的顏色。

我的問題是,我不知道如何改變根據遊戲模式橢圓的顏色。

我想我應該使用數據綁定,但我必須結合數據前的顏色從類型令牌轉換爲類型SolidBrushColor。我認爲它可以使用一些DataObjectProvider對象來實現,但它似乎過於複雜創造這樣一個簡單的任務42 DataObjectProvider對象...

那麼會根據最佳pratices是正確的解決方案?

+0

在這裏給了很多幫助,沒有答案接受甚至upvoted?我認爲[upvote是一種更正確的方式來說謝謝](http://stackoverflow.com/help/someone-answers)在這個網站 – har07

+0

對不起,但由於面試,我幾天沒有。我很快就會回到代碼。 – Vincent

+0

所以這就是原因。沒關係,只需要你的時間。我上面的評論是*只是在案件* .. – har07

回答

3

你會想在後端使用某種ViewModel,然後利用DataBinding。

假設代表Connect Four板的以下(設計)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來代表你的板子。

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。
  • 使用ItemsPanel和UniformGrid進行備份。
  • 在SquareViewModel中實現INotifyPropertyChanged,以便當令牌的值更改時,View代表該值。
  • d:DataContext屬性的用法,它將窗體的設計時間DataContext設置爲BoardViewModel的實例(將自身初始化爲隨機標記)。

在運行時,你會想你的主板查看的DataContext設置爲BoardViewModel的真實實例(或任何你的視圖模型的叫法),但如何改變的顏色的基本思路令牌存在。

+0

如果我理解正確,這種模式是侵入性的,對吧?有沒有辦法建立一個獨立於框架的模型? ModelView可以從GameState中檢索數據嗎? – Vincent

+0

在MVVM中,你有3層。 View,ViewModel和Model。模型包含邏輯,視圖模型知道如何將模型信息轉換爲視圖需要的格式,視圖位於頂部。在您的具體情況中,您可以輕鬆擁有一個將GameState信息轉換爲View需要的格式的GameStateViewModel。 –

0

是的,你應該使用數據綁定。您應該將Fill顏色綁定到您的模型,並使用ValueConverter在枚舉和顏色之間進行轉換。或者在ViewModel上有一個Color屬性並直接綁定到該屬性。

我想用Grid是錯誤的做法,你應該(列表的列表其實,對於行和列)您的主板型號爲列表令牌,然後使用ItemsControlItemsTemplate創建板。這意味着重複性更低的XAML。

當你正在努力學習WPF和XAML,嘗試使用Google上面,看看你走多遠。

1

如果Token是一個具有顏色枚舉屬性的類,則可以在Token類中添加另一個類型爲string的屬性。在屬性的getter中,根據顏色枚舉屬性返回一個有效的顏色名稱字符串。有了這個,你可以將每個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(你也可以看到@ Heena的回答上INotifyPropertyChanged的例子)。

+0

謝謝你提到的MVVM模式。看起來我需要學習如何使用它。 – Vincent