动态调整二维网格

时间:2017-03-15 04:16:39

标签: c# wpf mvvm

我正致力于制作纸牌游戏" Memory"在WPF中。我在UI方面遇到了麻烦。我已经设置好了,当用户选择难度时,它会动态设置卡座的大小(4x4很容易,这就是我们将要工作/谈论的概念证明)。在选择不同的困难时,如何允许动态更改网格?

这是您设置难度的地方(所有卡片都用于测试目的..)

 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>

2 个答案:

答案 0 :(得分:1)

我更希望在ItemsControl上使用ListBox来获取XAML中的集合。我还要绑定集合的宽度并添加允许包装对象的包装器面板:

<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>

不要忘记添加CollWidth属性:

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

现在您可以轻松修改SetDificulty方法:

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);
    }
}

您不必担心该集合的Height。添加的<WrapPanel>会为您处理。您只需指定CollWidth,并且换页面板会在每行中放置CollWidth / 50个按钮

答案 1 :(得分:0)

您可以使用UniformGrid作为ListBox的ItemsPanel,并将其ColumnsRows属性绑定到视图模型中的属性:

<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>

注意,在Button的Content Binding上设置UpdateSourceTrigger=PropertyChanged是没有意义的。它只会对实际触发源属性更新的Bindings产生影响,即TwoWay或OneWayToSource Bindings。

在后面的代码中创建UI元素也是不好的做法,例如Image类的Card属性。更好地声明类型为ImageSource的属性,并在XAML中绑定Image控件的Source属性:

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>