2009-06-05 12 views
7

Ich bin sehr neu in WPF, also habe ich angefangen, ein sehr einfaches Speicherkartenspiel zu machen, nur um die Syntax und so zu lernen. Das Spiel ist, wo alle Karten nach unten zeigen, du drehst zwei um und wenn sie passen, entferne sie, ansonsten flipp sie wieder runter und versuche alle Karten in der kürzesten Anzahl von Flips zu entfernen. Wie gesagt, sehr einfach ... :)Tabellenlayout in WPF

Meine Frage ist, gibt es kein Tabellenelement wie in HTML, so dass ich die Karten leicht in ein einheitliches Layout setzen kann, anstatt mit Margen zu verwirren?

Antwort

10

Hier ist ein Beispiel mit der Verwendung der UniformGrid als Matt Hamilton vorgeschlagen.

Lassen Sie uns zunächst die Klassen und Daten erstellen, die wir verwenden werden. Jede Karte wird durch ein Kartenobjekt dargestellt werden, und ein Gesicht Eigenschaft hat:

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

Als nächstes werden wir eine Klasse benötigen, die unsere Sammlung von Karten hat, und eine Eigenschaft, die uns die Anzahl der Karten festlegen kann . Für die CardCollection können wir eine ObservableCollection verwenden, da dies automatisch die Benutzeroberfläche benachrichtigt, wenn eine Karte hinzugefügt oder entfernt wird. Die NumberOfCards-Eigenschaft benötigt eine eigene Methode, um die Benutzeroberfläche zu benachrichtigen. Hierfür können wir implement die Schnittstelle INotifyPropertyChanged verwenden. Wir wollen auch eine Eigenschaft, die die Anzahl der Zeilen/Spalten repräsentiert zu verwenden, dies wird nur die Quadratwurzel unserer NumberOfCards:

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 
} 


Schließlich können wir dies als unsere Datacontext im Fenster gesetzt , und binden Sie an unsere Cards-Klasse im XAML. Für den XAML habe ich ein einfaches ItemsControl verwendet, so dass es nicht auswählbar ist, und ich habe das DataTemplate als eine Schaltfläche festgelegt, so dass jede Karte angeklickt werden kann, das ist alles was benötigt wird!

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> 

Eine andere Sache, die ich empfehlen würde bei der Suche ist ContentControl3D Implementierung Josh Smith. Das kann Ihnen das "Flipping" Verhalten geben, das Sie in der Card Klasse implementieren möchten.

+0

Sehr schön! +1 ... hoffe das wird "akzeptiert"! –

+0

oh das ist super, vielen Dank! –

2

Ich würde UniformGrid für Ihr Szenario empfehlen. Eine schnelle Suche ergab this article, die einige Code und Screenshots enthält, die helfen könnten.

+0

Der beste Teil eines UniformGrid ist in der Lage, ItemsPanel ItemsControl zu setzen, um es zu verwenden. Dann können die Karten durch ItemsSorce gebunden werden und Sie müssen nicht jede Karte in XAML deklarieren. – rmoore

+0

Ich wollte den Benutzer fragen, wie viele Karten er spielen möchte und sie dann generieren, anstatt eine statische Anzahl von Karten im XAML zu haben. hast du einen Artikel für ItemsControl/ItemSource? –

+0

Ich kann nicht für @rmoore sprechen, aber ich nehme an, er spricht über die Verwendung eines UniformGrid als ItemsPanel für eine ListBox. Hier ist ein Artikel, der mit WrapPanel etwas Ähnliches macht: http://compilewith.net/2008/03/wpf-listbox-itemspaneltemplate-and.html –

0

Es gibt eine Tabelle in WPF, hier ist eine gute article zum Einstieg damit. Aus Erfahrung ist die Tabelle in WPF nicht so einfach zu verwenden und die Verwendung eines Grids ist im Allgemeinen eine bessere Option.

+1

Das Table-Objekt wird in TextBlocks und FlowDocuments und nicht so sehr in UI-Elementen verwendet. – YotaXP

Verwandte Themen