2009-06-05 16 views
7

Soy muy nuevo en WPF, así que acabo de comenzar a crear un juego de tarjeta de memoria muy simple para aprender la sintaxis y demás. El juego es donde todas las cartas están boca abajo, das dos vueltas y si coinciden, las quitas, de lo contrario las vuelves a poner e intentas quitar todas las cartas en el menor número de vueltas. Como dije, muy simple ... :)Diseño de tabla en WPF

Mi pregunta es, ¿no hay ningún elemento de tabla como en HTML para poder colocar fácilmente las tarjetas en un diseño uniforme en lugar de tener que meterme con los márgenes?

Respuesta

10

Aquí hay un ejemplo con UniformGrid como sugirió Matt Hamilton.

Primero, permitamos crear las clases y datos que vamos a utilizar. Cada tarjeta será representada por un objeto de tarjeta, y tienen una propiedad de la cara:

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

A continuación, vamos a necesitar una clase que tiene nuestra colección de tarjetas, y también tienen una propiedad que nos permite establecer el número de tarjetas . Para CardCollection podemos usar un ObservableCollection ya que automáticamente se notificará a la UI cuando se agregue o elimine una Tarjeta. La propiedad NumberOfCards necesitará su propio método para notificar a la IU, para esto podemos implement la interfaz INotifyPropertyChanged. También vamos a querer una propiedad que representa el número de filas/columnas a utilizar, esto sólo será la raíz cuadrada de nuestros 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 
} 


Por último, podemos establecer esto como nuestros DataContext en la ventana , y se unen a nuestra clase Cards en el XAML. Para el XAML utilicé un SimpleControl simple, para que no se pueda seleccionar, y configuré el DataTemplate como un botón, de modo que se pueda hacer clic en cada tarjeta, ¡eso es todo lo que se necesita!

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> 

Otra cosa que yo recomendaría viendo es ContentControl3D aplicación de Josh Smith. Como eso puede darle el comportamiento de 'inversión' que está buscando implementar en la clase de Tarjeta bastante bien.

+0

¡Muy bien! +1 ... ¡espero que esto sea "aceptado"! –

+0

oh esto es increíble, ¡muchas gracias! –

2

Recomendaría UniformGrid para su situación. Una búsqueda rápida produjo this article que incluye algunos códigos y capturas de pantalla que podrían ayudar.

+0

La mejor parte de un UniformGrid es poder establecer un ItemsPatrol de ItemsPanel para usarlo. Luego, las tarjetas se pueden enlazar a través de ItemsSorce y no es necesario que declares cada carta en XAML. – rmoore

+0

Iba a preguntarle al usuario con cuántas tarjetas quería jugar y luego generarlas en lugar de tener un número estático de cartas en el XAML. ¿Tiene un artículo para ItemsControl/ItemSource? –

+0

No puedo hablar por @rmoore, pero entiendo que está hablando de usar un UniformGrid como el ItemsPanel para un ListBox. Aquí hay un artículo que hace algo similar con WrapPanel: http://compilewith.net/2008/03/wpf-listbox-itemspaneltemplate-and.html –

0

Hay una tabla en WPF, aquí hay una buena article al comenzar a usarla. Por experiencia, la Tabla en WPF no es tan fácil de usar y usar una Grilla generalmente es una mejor opción.

+1

El objeto Table se usa en TextBlocks y FlowDocuments, y no tanto en elementos UI. – YotaXP

Cuestiones relacionadas