2009-06-05 19 views
7

WPF'ye çok yeni geldim, bu yüzden sadece sözdizimini öğrenmek için çok basit bir hafıza kartı oyunu yapmaya başladım. Oyun, tüm kartların aşağı baktığı, ikiyi çevirdiğiniz ve onları eşleştirdiğiniz takdirde onları kaldırdığınız, aksi halde onları geri göndereceğiniz ve en kısa sayıdaki tüm saydamları çıkarmaya çalıştığınız yerdir. Dediğim gibi, çok basit ... :)WPF'de tablo düzeni

Sorum şu ki, HTML gibi bir tablo öğesi yok mu, bu yüzden kenar boşluklarıyla uğraşmak yerine kartları düzgün bir düzende kolayca yerleştirebiliyorum?

cevap

10

Matt Hamilton'ın önerdiği gibi UniformGrid'i kullanan bir örnek.

İlk olarak, kullanacağımız sınıfları ve verileri oluşturmanızı sağlar. Her kartın bir kart nesnesi tarafından temsil edilir ve bir yüz özelliği vardır edilecektir:

public class Card 
{ 
    public string Face { get; set; } 
    public Card() { } 
} 

İleri, bize kartların sayısını ayarlamak sağlayan Kartları koleksiyonumuzu bulunan bir sınıf ve ayrıca bir özellik gerekecektir . CardCollection için bir ObservableCollection kullanabiliriz, çünkü bir Kart eklendiğinde veya çıkarıldığında UI'yi otomatik olarak bilgilendirir. NumberOfCards özelliği, kullanıcı arabirimini bilgilendirmek için kendi yöntemine gereksinim duyacaktır, bunun içinINotifyPropertyChanged arabirimini kullanabiliriz. Nihayet

public class Cards : INotifyPropertyChanged 
{ 
    private int myNumberOfCards; 
    public int NumberOfCards 
    { 
     get { return this.myNumberOfCards; } 
     set 
     { 
      this.myNumberOfCards = value; 
      NotifyPropertyChanged("NumberOfCards"); 

      // Logic is going in here since this is just an example, 
      // Though I would not recomend hevily modifying the setters in a finalized app. 
      while (this.myNumberOfCards > CardCollection.Count) 
      { 
       CardCollection.Add(new Card { Face = (CardCollection.Count + 1).ToString() }); 
      } 
      while (this.myNumberOfCards < CardCollection.Count) 
      { 
       CardCollection.RemoveAt(CardCollection.Count - 1); 
      } 

      NotifyPropertyChanged("CardColumns"); 
     } 
    } 
    public int CardColumns 
    { 
     get 
     { 
      return (int)Math.Ceiling((Math.Sqrt((double)CardCollection.Count))); 
     } 
    } 
    private ObservableCollection<Card> myCardCollection; 
    public ObservableCollection<Card> CardCollection 
    { 
     get 
     { 
      if (this.myCardCollection == null) 
      { this.myCardCollection = new ObservableCollection<Card>(); } 
      return this.myCardCollection; 
     } 
    } 
    public Cards(int initalCards) 
    { 
     NumberOfCards = initalCards; 
    } 

    #region INotifyPropertyChanged Members 

    public event PropertyChangedEventHandler PropertyChanged; 

    private void NotifyPropertyChanged(String info) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(info)); 
     } 
    } 

    #endregion 
} 


, biz Pencerede bizim DataContext olarak ayarlayabilirsiniz: Biz de kullanmak Satırlar/Sütunlar sayısını temsil eden bir özellik isteyeceksiniz, bu sadece bizim NumberOfCards karekökü olacak ve XAML'deki Kartlar sınıfına bağlanır. XAML için basit bir ItemsControl kullandı, bu yüzden seçilemez ve DataTemplate'i bir düğme olarak ayarladım, böylece her kartın üzerine tıklanabilir, hepsi bu kadar gerekli! Ben bakarak tavsiye ederim

public partial class Window1 : Window 
{ 
    public Window1() 
    { 
     InitializeComponent(); 
     this.DataContext = new Cards(25); 
    } 
} 

<Window x:Class="Sample_BoolAnimation.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1" 
    Height="300" 
    Width="300"> 
    <Grid> 
     <DockPanel> 
      <DockPanel DockPanel.Dock="Top"> 
       <TextBlock Text="Number of Cards:" /> 
       <TextBox Text="{Binding NumberOfCards, UpdateSourceTrigger=PropertyChanged}" /> 
      </DockPanel> 
      <ItemsControl ItemsSource="{Binding CardCollection}"> 
       <ItemsControl.ItemsPanel> 
        <ItemsPanelTemplate> 
         <UniformGrid Columns="{Binding CardColumns}" /> 
        </ItemsPanelTemplate> 
       </ItemsControl.ItemsPanel> 
       <ItemsControl.ItemTemplate> 
        <DataTemplate> 
         <Button Content="{Binding Face}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" /> 

        </DataTemplate> 
       </ItemsControl.ItemTemplate> 
      </ItemsControl> 
     </DockPanel> 
    </Grid> 
</Window> 

başka şey Josh Smith'in ContentControl3D uygulamasıdır. Bu size Card sınıfında uygulamak için aradığınız 'saygısız' davranışı oldukça güzel verebilir.

+0

Çok güzel! +1 ... umarım bu "kabul" edilir! –

+0

oh bu harika, çok teşekkür ederim! –

2

Senaryo için UniformGrid öneririm. Hızlı bir arama, yardımcı olabilecek bazı kod ve ekran görüntüleri içeren this article'u verdi.

+0

UniformGrid'in en iyi parçası, kullanmak için ItemsControl öğesinin ItemsPanel değerini ayarlayabilmektir. Daha sonra kartlar ItemsSorce'a bağlanabilir ve her kartı XAML'de bildirmeniz gerekmez. – rmoore

+0

Kullanıcıya kaç tane kart oynamayı istediklerini sordum ve daha sonra XAML'de statik bir kart sayısına sahip olmak yerine bunları üretecektim. ItemsControl/ItemSource için bir makaleniz var mı? –

+0

@rmoore için konuşamıyorum, ama bir UnisexGrid'i bir ListBox için ItemsPanel olarak kullanmaktan bahsediyor. Burada WrapPanel ile benzer bir şey yapan bir makale var: http://compilewith.net/2008/03/wpf-listbox-itemspaneltemplate-and.html –

0

WPF'de bir Masa var, başlangıçta iyi bir article. Deneyimden WPF'deki Tablo, kullanımı kolay ve bir Grid kullanmak genellikle daha iyi bir seçenektir.

+1

Tablo nesnesi, TextBlocks ve FlowDocuments öğelerinde ve çok fazla UI öğesi kullanılmamaktadır. – YotaXP