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.
¡Muy bien! +1 ... ¡espero que esto sea "aceptado"! –
oh esto es increíble, ¡muchas gracias! –