2017-03-15 1 views
0

Ich arbeite an der Erstellung des Kartenspiels "Memory" in WPF. Ich habe Probleme auf der UI-Seite davon. Ich habe es so eingerichtet, dass, wenn der Benutzer einen Schwierigkeitsgrad auswählt, er dynamisch die Größe des Decks einstellt (4x4 für einfach, woran wir arbeiten werden/worüber wir sprechen werden, um den Konzeptnachweis zu führen). Wie erlaube ich die dynamische Änderung des Gitters bei der Auswahl verschiedener Schwierigkeiten?Dynamische Dimensionierung 2 Dimensional Grid

Hier können Sie die Schwierigkeit (Alle Karten sind für Testzwecke ..) eingestellt

private void SetDifficulty(Difficulty difficulty) { 
     //Clearing CardList 
     CardList.Clear(); 
     //Switching on the diff 
     switch (difficulty) { 
      case Difficulty.Easy: 
       CardList = new ObservableCollection<Card>{ 
        new Card { 
         Image = Resources.Bowser 
        }, 
        new Card(), 
        new Card(), 
        new Card(), 
        new Card(), 
        new Card(), 
        new Card(), 
        new Card(), 
        new Card(), 
        new Card(), 
        new Card(), 
        new Card(), 
        new Card(), 
        new Card(), 
        new Card(), 
        new Card() 
       }; 

       break; 
      case Difficulty.Medium: 
       break; 
      case Difficulty.Hard: 
       break; 
      default: 
       throw new ArgumentOutOfRangeException(nameof(difficulty), difficulty, null); 
     } 
    } 

XAML:

<Window x:Class="MemoryGame.Views.MainView" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:local="clr-namespace:MemoryGame.Views" 
    xmlns:viewModels="clr-namespace:MemoryGame.ViewModels" 
    mc:Ignorable="d" 
    d:DataContext="{d:DesignInstance viewModels:MemoryGameViewModel}" 
    Title="MainView" Height="300" Width="300"> 
<Grid ShowGridLines="True"> 
    <ListBox ItemsSource="{Binding Path=CardList}"> 
     <ListBox.ItemTemplate> 
      <DataTemplate DataType="viewModels:Card"> 
       <StackPanel Orientation="Horizontal" Width="50" Height="50" > 
        <!--<Image Source="/Pictures/Luigi.jpg"></Image>--> 
        <Button Content="{Binding Image, UpdateSourceTrigger=PropertyChanged}" Margin="5" Height="50" Width="50"> 
        </Button> 
       </StackPanel> 
      </DataTemplate> 
     </ListBox.ItemTemplate> 
    </ListBox> 
</Grid> 

+0

Warum nicht initialisiert werden sie in einem for-Schleife? – Everyone

+0

ist es wahrscheinlich einfacher, UniformGrid, z.B. ''. Die Spalten- und Zeileneigenschaften unterstützen die Bindung, die Änderung der Quellwerte und die Boardgröße wird aktualisiert. – ASh

+0

Ich plante dies, ich fügte sie nur zum Testen hinzu, aber die Schleife wäre noch einfacher gewesen. – ReRoute

Antwort

1

ich lieber ItemsControl über ListBox für die Verwendung von die Sammlung im XAML. Ich würde auch die Breite der Sammlung BIND und Wrapper-Panel hinzufügen, die zum Verpacken von Objekten erlaubt:

<ItemsControl ItemsSource="{Binding Path=CardList} Width="{Binding CollWidth}"> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate DataType="viewModels:Card"> 
      <StackPanel Orientation="Horizontal" Width="50" Height="50" > 
       <!--<Image Source="/Pictures/Luigi.jpg"></Image>--> 
       <Button Content="{Binding Image, UpdateSourceTrigger=PropertyChanged}" Margin="5" Height="50" Width="50"> 
       </Button> 
      </StackPanel> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate> 
    <ItemsControl.ItemsPanel> 
     <ItemsPanelTemplate> 
       <!-- A WrapPanel ensures the items wrap to the next line --> 
       <!-- when it runs out of room in the collection dimensions --> 
       <WrapPanel Orientation="Horizontal"/> 
     </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
</ItemsControl> 

Vergessen Sie nicht CollWidth Eigenschaft hinzufügen:

private int _collWidth; 
    public int CollWidth { 
     get { return _collWidth; } 
     set { 
      _collWidth = value; 
      OnPropertyChanged("CollWidth"); 
     } 
    } 

Jetzt können Sie einfach Ihre SetDificulty Methode ändern :

private void SetDifficulty(Difficulty difficulty) { 
    // this auto clears everything 
    CardList = new ObservableCollection<Card>(); 
    //Switching on the diff 
    switch (difficulty) { 
     case Difficulty.Easy: 
      // set the width in each level of difficulty to allow wrapper to make nice looking grid 
      CollWidth = 200; // (button width is 50) * 4 buttons = 200 
      for(int i=0;i<16;i++) 
       CardList.Add(new Card()); // or whatever constructor 
      break; 
     case Difficulty.Medium: 
      CollWidth = 250; // (button width is 50) * 5 buttons = 250 
      for(int i=0;i<25;i++) 
       CardList.Add(new Card()); // or whatever constructor 
      break; 
     case Difficulty.Hard: 
      CollWidth = 300; // (button width is 50) * 6 buttons = 300 
      for(int i=0;i<36;i++) 
       CardList.Add(new Card()); // or whatever constructor 
      break; 
     default: 
      throw new ArgumentOutOfRangeException(nameof(difficulty), difficulty, null); 
    } 
} 

Sie müssen die Sammlung keine Sorge über die Height von. Der hinzugefügte <WrapPanel> wird sich darum kümmern. Sie legen fest, nur die CollWidth und die Wickelplatte CollWidth/50 Tasten in jeder Reihe stellen wird

+0

Vielen Dank. Das ist genau das, was ich wollte. Ich landete tatsächlich ein Tag innerhalb der Schaltfläche und binden Sie es an die Image-Eigenschaft, aber für den Rest davon. Perfekt. – ReRoute

+0

@ChaseB Froh, ich könnte helfen.Wenn Sie denken, dass es die Antwort ist, bitte ich Sie, es auszuwählen :) Danke :) – Everyone

0

Sie eine UniformGrid als Itemspanel Ihrer List-Box verwenden könnte, und binden ihre Columns oder Rows Eigenschaft auf eine Eigenschaft in Ihrer Ansicht Modell:

<ListBox ItemsSource="{Binding CardList}"> 
    <ListBox.ItemsPanel> 
     <ItemsPanelTemplate> 
      <UniformGrid Columns="{Binding GridSize}"/> 
     </ItemsPanelTemplate> 
    </ListBox.ItemsPanel> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <Button Content="{Binding Image}" Margin="5" Height="50" Width="50"/> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

Als Hinweis, macht keinen Sinn Bindung des Button UpdateSourceTrigger=PropertyChanged auf dem Content einstellen. Es wirkt sich nur auf Bindungen aus, die tatsächlich eine Aktualisierung ihrer Quelleigenschaft auslösen, d. H. TwoWay- oder OneWayToSource-Bindungen.

Es ist auch schlechte Praxis, UI-Elemente in Code hinter, wie die Image Eigenschaft Ihrer Card Klasse zu erstellen. Besser erklären eine Eigenschaft vom Typ ImageSource und Binden einer Source Eigenschaft Bildsteuerung in XAML:

public class Card 
{ 
    public ImageSource Image { get; set; } 
    ... 
} 

... 
var card = new Card 
{ 
    Image = new BitmapeImage(new Uri("pack://application:,,,/Picures/Luigi.jpg")) 
}; 

XAML:

<ListBox.ItemTemplate> 
    <DataTemplate> 
     <Button Margin="5" Height="50" Width="50"> 
      <Image Source="{Binding Image}"/> 
     </Button> 
    </DataTemplate> 
</ListBox.ItemTemplate> 
+0

Ja, das Bild war nur ein Hack, weil ich mit dem Versuch kämpfte, es zu bekommen, zu zeigen. Leider ist dies mein erstes WPF-Projekt und ich kenne noch nicht alles. Vielen Dank für die Tipps. – ReRoute