wpf 在 UWP Xaml 中创建和填充 NxN 网格

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33589510/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 13:31:25  来源:igfitidea点击:

Creating and filling a NxN grid in UWP Xaml

c#wpfxamluwp

提问by fsp

I am trying to create a UWP puzzle game, I want to cut the picture into n parts and then show the pieces in a grid.

我正在尝试创建一个 UWP 益智游戏,我想将图片切成 n 部分,然后在网格中显示这些部分。

My problem is, how to force a certain NxN style. Right now I have to maximize the window in order to see a 3x3 grid, if I shrink either side, it will converge to a 2 column, 1 column grid. Is there a way to handle this?

我的问题是,如何强制某种 NxN 风格。现在我必须最大化窗口才能看到一个 3x3 的网格,如果我缩小任一侧,它会收敛到一个 2 列、1 列的网格。有没有办法处理这个问题?

This is what I have done, I know the RowDefinition is manually right now, until I figure out a better way to do that.

这就是我所做的,我知道 RowDefinition 现在是手动的,直到我想出更好的方法来做到这一点。

<UserControl
    x:Class="PictureSplitter.Views.PictureView"
    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"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400">


        <GridView ItemsSource="{Binding Splitter.PuzzlePositions}">

            <GridView.ItemTemplate>
                <DataTemplate>
                    <Border BorderBrush="Red" BorderThickness="2">
                    <Grid x:Name="picGrid">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"></RowDefinition>
                            <RowDefinition Height="Auto"></RowDefinition>
                            <RowDefinition Height="Auto"></RowDefinition>
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto"></ColumnDefinition>
                            <ColumnDefinition Width="Auto"></ColumnDefinition>
                            <ColumnDefinition Width="Auto"></ColumnDefinition>
                        </Grid.ColumnDefinitions>
                        <Image Source="{Binding Piece.ImageSource}" />
                    </Grid>
                </Border>
                </DataTemplate>
            </GridView.ItemTemplate>

        </GridView>

</UserControl>

This are two example images: Wanted gridstyle

这是两个示例图像: 通缉网格样式

Not wanted gridstyle

不想要的网格样式

采纳答案by Romasz

There are probably couple of ways to do that, here is another one. I've modified the UserControlso that it automatically adjusts items size to show them as square grid, when page size changes and/or collection changes.

可能有几种方法可以做到这一点,这里是另一种。我修改了UserControl,以便在页面大小更改和/或集合更改时自动调整项目大小以将它们显示为方形网格。

The UserControl XAML code:

用户控件 XAML 代码:

<UserControl
    x:Class="MyControls.MyUserControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MyControls"
    Name="myControl">

    <GridView Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" ItemsSource="{Binding ElementName=myControl, Path=Items}"
              Width="{Binding ElementName=myControl, Path=CurrentWidth}" HorizontalAlignment="Center"
              Height="{Binding Width, RelativeSource={RelativeSource Self}}">
        <GridView.ItemContainerStyle>
            <Style TargetType="GridViewItem">
                <Setter Property="Margin" Value="0"/>
            </Style>
        </GridView.ItemContainerStyle>
        <GridView.ItemTemplate>
            <DataTemplate>
                <Border Padding="10" Width="{Binding ElementName=myControl, Path=ElementSize}" Height="{Binding ElementName=Width, RelativeSource={RelativeSource Self}}">
                    <Border BorderBrush="Red" BorderThickness="3">
                        <Image Source="ms-appx:///Assets/StoreLogo.png" Stretch="UniformToFill"/>
                    </Border>
                </Border>
            </DataTemplate>
        </GridView.ItemTemplate>
    </GridView>
</UserControl>

UserControl code behind:

背后的用户控制代码:

public sealed partial class MyUserControl : UserControl, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private void RaiseProperty(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));

    public IList Items
    {
        get { return (IList)GetValue(ItemsProperty); }
        set { SetValue(ItemsProperty, value); }
    }

    public static readonly DependencyProperty ItemsProperty =
        DependencyProperty.Register("Items", typeof(IList), typeof(MyUserControl),
            new PropertyMetadata(0, (s, e) =>
            {
                if (Math.Sqrt((e.NewValue as IList).Count) % 1 != 0)
                    Debug.WriteLine("Bad Collection");
            }));

    public void Items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (Math.Sqrt(Items.Count) % 1 != 0) Debug.WriteLine("Bad Collection");
        RaiseProperty(nameof(ElementSize));
    }

    private double currentWidth;
    public double CurrentWidth
    {
        get { return currentWidth; }
        set { currentWidth = value; RaiseProperty(nameof(CurrentWidth)); RaiseProperty(nameof(ElementSize)); }
    }

    public double ElementSize => (int)(currentWidth / (int)Math.Sqrt(Items.Count)) - 1;

    public MyUserControl()
    {
        this.InitializeComponent();
    }
}

The MainPage XAML:

主页 XAML:

<Grid>
    <local:MyUserControl x:Name="myControl" Items="{Binding MyItems}"/>
    <Button Content="Add" Click="Button_Click"/>
</Grid>

MainPage code behind:

后面的主页代码:

public sealed partial class MainPage : Page
{
    private ObservableCollection<int> myItems = new ObservableCollection<int> { 1, 2, 3, 4, 5, 6, 7, 8 };
    public ObservableCollection<int> MyItems
    {
        get { return myItems; }
        set { myItems = value; }
    }

    public MainPage()
    {
        this.InitializeComponent();
        DataContext = this;
        MyItems.CollectionChanged += myControl.Items_CollectionChanged;
    }

    protected override Size MeasureOverride(Size availableSize)
    {
        myControl.CurrentWidth = Math.Min(availableSize.Height, availableSize.Width);
        return base.MeasureOverride(availableSize);
    }

    private void Button_Click(object sender, RoutedEventArgs e) => MyItems.Add(3);
}

The program starts with "Bad Collection" - there are 8 items, so you can't make a square grid from them, but as soon as you click the provided button - the collection's count changes to 9 and the grid should update itself.

该程序以“Bad Collection”开始 - 有 8 个项目,因此您无法从它们制作方形网格,但是一旦您单击提供的按钮 - 集合的计数更改为 9,并且网格应自行更新。

回答by tgpdyk

It looks like you are doing this by way of MVVM, so I think you need to have a property for your Rows and Columns from your ViewModel. And then you need to have a Converter to supply the coordinate for your pieces .... OR an Attached property.

看起来您是通过 MVVM 执行此操作的,因此我认为您需要为 ViewModel 中的行和列设置一个属性。然后你需要有一个转换器来为你的作品提供坐标......或附加属性。

This will give you an idea:

这会给你一个想法:

<Window.Resources>
    <System:Int64 x:Key="X">3</System:Int64>
    <System:Int64 x:Key="Y">3</System:Int64>
</Window.Resources>

<Grid x:Name="myGrid" Loaded="Grid_Loaded">
    // You can bind column and row
    // <Button Content="image1" Grid.Column="{Binding column}" Grid.Row="{Binding row}"/>

    <Button Content="image1" Grid.Column="0" Grid.Row="0"/>
    <Button Content="image2" Grid.Column="1" Grid.Row="0"/>
    <Button Content="image3" Grid.Column="2" Grid.Row="0"/>

    <Button Content="image4" Grid.Column="0" Grid.Row="1"/>
    <Button Content="image5" Grid.Column="1" Grid.Row="1"/>
    <Button Content="image6" Grid.Column="2" Grid.Row="1"/>

    <Button Content="image7" Grid.Column="0" Grid.Row="2"/>
    <Button Content="image8" Grid.Column="1" Grid.Row="2"/>
    <Button Content="image9" Grid.Column="2" Grid.Row="2"/>
</Grid>

private void Grid_Loaded(object sender, RoutedEventArgs e)
{
    Int64 X = (Int64) this.FindResource("X");
    Int64 Y = (Int64) this.FindResource("Y");

    for (Int64 i = 0; i < X; i++)
    { 
        ColumnDefinition c = new ColumnDefinition();
        myGrid.ColumnDefinitions.Add(c);
    }
    for (Int64 i = 0; i < (int)Y; i++)
    {
        RowDefinition r = new RowDefinition();
        myGrid.RowDefinitions.Add(r);
    }
}

回答by AnjumSKhan

I have used a ListView with GridView as it's View property. And it is working fine.

我使用了带有 GridView 的 ListView 作为它的 View 属性。它工作正常。

<ListView x:Name="ImageList" Width="210" Height="210">
    <ListView.View>
       <GridView>
          <GridView.ColumnHeaderContainerStyle>
            <Style TargetType="Control">
                <Setter Property="Visibility" Value="Collapsed"/>
            </Style>
          </GridView.ColumnHeaderContainerStyle>
          <GridViewColumn>                            
             <GridViewColumn.CellTemplate>
                  <DataTemplate>
                       <Image Source="{Binding sq1}"/>
                  </DataTemplate>
             </GridViewColumn.CellTemplate>
           </GridViewColumn>
           <GridViewColumn >
             <GridViewColumn.CellTemplate>
                   <DataTemplate>
                       <Image Source="{Binding sq2}"/>
                   </DataTemplate>
              </GridViewColumn.CellTemplate>
            </GridViewColumn>

            <GridViewColumn >
                <GridViewColumn.CellTemplate>
                     <DataTemplate>
                         <Image Source="{Binding sq3}"/>
                     </DataTemplate>
                 </GridViewColumn.CellTemplate>
             </GridViewColumn>    
       </GridView>
  </ListView.View>

var imgBox = new BitmapImage(new Uri(@"/images/cellbkg.jpg", UriKind.Relative));
var source = new[] { new { sq1 = imgBox, sq2 = imgBox, sq3 = imgBox }, new { sq1 = imgBox, sq2 = imgBox, sq3 = imgBox }, new { sq1 = imgBox, sq2 = imgBox, sq3 = imgBox } };    
ImageList.ItemsSource = source;

This code produces below output, and don't get collapsed if you reduce window size :

此代码产生以下输出,如果您减小窗口大小,则不会折叠:

3x3 matrix display

3x3 矩阵显示

If this is what you want, you can add columns dynamically using below approach. For NxN matrix, you have to add only N columns, binding will take care of rest :

如果这是您想要的,您可以使用以下方法动态添加列。对于 NxN 矩阵,您只需添加 N 列,绑定将处理其余部分:

        GridView view = (GridView)ImageList.View;
        view.Columns.Add(new GridViewColumn());