在 UWP 中创建并填充 NxN 网格 Xaml
Creating and filling a NxN grid in UWP Xaml
我正在尝试创建一个 UWP 益智游戏,我想将图片切割成 n 个部分,然后将这些部分显示在网格中。
我的问题是,如何强制使用某种 NxN 样式。现在我必须最大化 window 才能看到 3x3 网格,如果我缩小任一侧,它将收敛到 2 列、1 列网格。有办法处理吗?
这就是我所做的,我知道 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>
这是两个示例图片:
看起来您是通过 MVVM 执行此操作的,因此我认为您需要为 ViewModel 中的行和列设置一个 属性。然后你需要有一个转换器来为你的作品提供坐标....或者一个附加的 属性.
这会给你一个想法:
<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);
}
}
我将 ListView 与 GridView 一起使用,因为它是视图 属性。它工作正常。
<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;
此代码产生以下输出,并且如果您减小 window 大小也不会折叠:
如果这是您想要的,您可以使用以下方法动态添加列。对于 NxN 矩阵,您只需添加 N 列,绑定将处理其余部分:
GridView view = (GridView)ImageList.View;
view.Columns.Add(new GridViewColumn());
可能有几种方法可以做到这一点,这是另一种方法。我已经修改了 UserControl 以便当页面大小更改 and/or 集合更改时,它会自动调整项目大小以将它们显示为方形网格。
用户控件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代码:
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();
}
}
主页XAML:
<Grid>
<local:MyUserControl x:Name="myControl" Items="{Binding MyItems}"/>
<Button Content="Add" Click="Button_Click"/>
</Grid>
MainPage后面的代码:
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);
}
程序以 "Bad Collection" 开头 - 有 8 个项目,因此您无法将它们制成正方形网格,但只要您单击提供的按钮 - 集合的计数就会变为 9,并且网格应自行更新。
我正在尝试创建一个 UWP 益智游戏,我想将图片切割成 n 个部分,然后将这些部分显示在网格中。
我的问题是,如何强制使用某种 NxN 样式。现在我必须最大化 window 才能看到 3x3 网格,如果我缩小任一侧,它将收敛到 2 列、1 列网格。有办法处理吗?
这就是我所做的,我知道 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>
这是两个示例图片:
看起来您是通过 MVVM 执行此操作的,因此我认为您需要为 ViewModel 中的行和列设置一个 属性。然后你需要有一个转换器来为你的作品提供坐标....或者一个附加的 属性.
这会给你一个想法:
<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);
}
}
我将 ListView 与 GridView 一起使用,因为它是视图 属性。它工作正常。
<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;
此代码产生以下输出,并且如果您减小 window 大小也不会折叠:
如果这是您想要的,您可以使用以下方法动态添加列。对于 NxN 矩阵,您只需添加 N 列,绑定将处理其余部分:
GridView view = (GridView)ImageList.View;
view.Columns.Add(new GridViewColumn());
可能有几种方法可以做到这一点,这是另一种方法。我已经修改了 UserControl 以便当页面大小更改 and/or 集合更改时,它会自动调整项目大小以将它们显示为方形网格。
用户控件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代码:
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();
}
}
主页XAML:
<Grid>
<local:MyUserControl x:Name="myControl" Items="{Binding MyItems}"/>
<Button Content="Add" Click="Button_Click"/>
</Grid>
MainPage后面的代码:
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);
}
程序以 "Bad Collection" 开头 - 有 8 个项目,因此您无法将它们制成正方形网格,但只要您单击提供的按钮 - 集合的计数就会变为 9,并且网格应自行更新。