2009-06-05 2 views
7

Я очень новичок в WPF, поэтому я только начал создавать очень простую карточную игру с карточкой, чтобы узнать синтаксис и т. Д. В игре все карты обращены вниз, вы переворачиваете два, и если они совпадают, вы удаляете их, иначе переверните их и попробуйте удалить все карты в кратчайшее количество флип. Как я уже сказал, очень просто ... :)Настольная компоновка в WPF

Мой вопрос в том, нет ли элемента таблицы, например, в HTML, поэтому я могу легко поместить карты в единый формат вместо того, чтобы путаться с полями?

ответ

10

Вот пример с ним, используя UniformGrid, как предположил Мэтт Гамильтон.

Во-первых, давайте создадим классы и данные, которые мы будем использовать. Каждая карта будет представлена ​​объектом карты, и имеет свойство лица:

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

Далее, нам потребуются класс, который имеет нашу коллекцию карт, а также свойство, которое позволяет нам установить количество карт , Для CardCollection мы можем использовать ObservableCollection, так как автоматически будет уведомлять пользовательский интерфейс при добавлении или удалении Карты. Свойству NumberOfCards потребуется собственный метод для уведомления пользовательского интерфейса, для этого мы можем использовать implement интерфейс INotifyPropertyChanged. Мы также хотим, свойство, представляющее число строк/столбцов для использования, это будет просто квадратный корень из наших 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 
} 


Наконец, мы можем установить это как наши DataContext в окне , и привязать к нашему классу карт в XAML. Для XAML я использовал простой элемент ItemsControl, так что он не выбирается, и я устанавливаю DataTemplate как кнопку, так что на каждую карту можно щелкнуть, вот и все, что нужно!

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> 

Другое дело, что я бы рекомендовал смотреть на это ContentControl3D реализация Джоша Смита. Так как это может дать вам «перевернутое» поведение, которое вы ищете для реализации в классе карты довольно хорошо.

+0

Очень приятно! +1 ... надеюсь, что это «принято»! –

+0

О, это потрясающе, спасибо вам большое! –

2

Я бы порекомендовал UniformGrid для вашего сценария. Быстрый поиск дал this article, который включает в себя код и скриншоты, которые могут помочь.

+0

Лучшая часть UniformGrid может установить ItemsPanel ItemsControl для его использования. Затем карты могут быть связаны через ItemsSorce, и вам не нужно объявлять каждую карту в XAML. – rmoore

+0

Я собирался спросить у пользователя, сколько карточек они хотели играть, а затем генерировать их вместо того, чтобы иметь статическое количество карт в XAML. у вас есть статья для ItemsControl/ItemSource? –

+0

Я не могу говорить за @rmoore, но я понимаю, что он говорит об использовании UniformGrid в качестве ItemsPanel для ListBox. Вот статья, которая делает что-то похожее с WrapPanel: http://compilewith.net/2008/03/wpf-listbox-itemspaneltemplate-and.html –

0

Существует таблица в WPF, вот хороший article, начав с нее. По опыту таблица в WPF не так проста в использовании, и использование Grid обычно является лучшим вариантом.

+1

Объект Table используется в TextBlocks и FlowDocuments и не так много элементов интерфейса. – YotaXP

Смежные вопросы