我想实现:按钮排列成正方形(作为二维 NxN 数组)。单击按钮时,将旋转一行和一列中的所有按钮。数字 N 是可定制的。一开始我什么都做MainWindow.xaml.cs,他们建议我正常做一切并使用它MVVM。代码MainWindow.xaml.cs:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private Button[,] CreateButtons(int quantity)
{
Form.Rows = quantity;
Form.Columns = quantity;
Button[,] buttons = new Button[quantity, quantity];
for (int i = 0; i < quantity; i++)
{
for (int j = 0; j < quantity; j++)
{
buttons[i, j] = new Button();
buttons[i, j].Width = 100;
buttons[i, j].Height = 20;
buttons[i, j].Margin = new Thickness(5,80,0,0);
buttons[i, j].Click += new RoutedEventHandler(new_button_click);
}
}
return buttons;
}
void new_button_click(object sender, RoutedEventArgs e)
{
Button btn = sender as Button;
if (btn != null)
{
var rotateTransform = btn.RenderTransform as RotateTransform;
var transform = new RotateTransform(90 + (rotateTransform == null ? 0 : rotateTransform.Angle));
transform.CenterX = 50;
transform.CenterY = 10;
btn.RenderTransform = transform;
}
}
private void AddToWrapPanel(int quantity, Button[,] buttons)
{
for (int i = 0; i < quantity; i++)
for (int j = 0; j < quantity; j++)
{
Form.Children.Add(buttons[i, j]);
}
}
private int GetQuantityButtons()
{
ComboBoxItem item = (ComboBoxItem)comboBox1.SelectedItem;
int count = int.Parse((string)item.Content);
return count;
}
private void СreateButton_Click(object sender, RoutedEventArgs e)
{
if (Form.Children.Count > 0)
Form.Children.Clear();
int count = GetQuantityButtons();
Button[,] buttons = CreateButtons(count);
AddToWrapPanel(count, buttons);
}
}
现在我开始移动所有东西。
XAML:
<Window x:Class="Di.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:user="clr-namespace:Di"
Title="Сейф" Height="715.6" Width="840" Left="250" Top="10" Background="Silver" ResizeMode="CanMinimize"
TextOptions.TextFormattingMode="Display" Icon="Resources/Icon1.ico">
<Window.DataContext>
<user:MainWindowModel />
</Window.DataContext>
<Grid>
<ItemsControl Margin="0,30,0,0">
<UniformGrid x:Name="Form"/>
<WrapPanel Name="wrapPanel" Background="#FFF2F2F2" />
</ItemsControl>
<Button Content="Старт" Height="23" HorizontalAlignment="Left" Margin="457,12,0,0" Name="createButton" VerticalAlignment="Top" Width="75" Click="СreateButton_Click" Command="{Binding Seter}" />
<ComboBox Height="23" HorizontalAlignment="Left" Margin="368,12,0,0" Name="comboBox1" VerticalAlignment="Top" Width="74" SelectedIndex="0" RenderTransformOrigin="0.5,0.739">
<ComboBoxItem Content="{Binding Three}" />
<ComboBoxItem Content="{Binding Four}" />
<ComboBoxItem Content="{Binding Five}" />
<ComboBoxItem Content="{Binding Six}" />
</ComboBox>
<Label Content="{Binding Lvl}" HorizontalAlignment="Left" Margin="254,10,0,0" VerticalAlignment="Top"/>
</Grid>
代码VM:
public class MainWindowModel
{
public int Three { get; set; }
public int Four { get; set; }
public int Five { get; set; }
public int Six { get; set; }
public string Lvl { get; set; }
public MainWindowModel()
{
Three = 3;
Four = 4;
Five = 5;
Six = 6;
Lvl = "Сложность (3 - 6):";
}
private ICommand _seter;
public ICommand Seter
{
get
{
return _seter ?? (_seter = new RelayCommand(() =>
{
// действие при вызове команды
}));
}
}
}
到目前为止,只有这样.. 请帮助我转移并完成我计划的时刻。例如:如何VM在服务按钮中创建一个属性RotationAngle?单击“创建”然后使用它们时如何生成一组按钮?如何访问UniformGrid行数和列数并将其与所选中int的关联combobox?
我们先走吧。让我们构建一个虚拟机。我们将需要一个 VM 的基类,其中将有一个实现
INotifyPropertyChanged:(如果您正在使用某种 MVVM 框架,那么您可能已经定义了一个类似的基类。)
现在是一个单元格的 VM。我们需要知道什么?旋转角度 - 让我们用 INPC 从中创建一个属性。行和列 - 这些属性是不可变的。以及激活单元格时将调用的命令。(她也是一成不变的。)
单击单元格时将执行的操作不能由单元格本身执行,因为许多单元格会旋转。因此,我们会将反应作为参数传递给“来自上方”的动作。我们得到这段代码:
下一个 VM 是整个电路板。她将不得不对细胞的轮换做出决定。我们需要什么数据?需要宽度和高度,更改时需要重新创建单元格数组。我们需要细胞本身,因为细胞只会作为一个整体被替换,所以我们不取
ObservableCollection<CellVM>,而是简单地取IEnumerable<CellVM>。方阵是不可能暴露在外面的,谁也不知道怎么附和上去。因此,我们将所有“合并”的单元格公开到一个公共序列中。接下来,当更改行数或列数时,我们需要重新生成单元格。
...并将其设置为随机起始角度:
现在是激活单元格时调用的函数。我们需要旋转同一列和同一行中的所有单元格。在第二个循环中,我们跳过已经旋转的单元格。
好的,VM 或多或少是清楚的。让我们继续查看。
我们需要
ItemsControl,因为我们想要显示一系列元素。我们有一个包含在属性中的元素序列AllCells。接下来,我们需要将单元格放入
UniformGrid. 我们选择作为载体UniformGrid,同时绑定行数和列数:此外,如何显示单独的单元格?你要
Button,就给。我们写DataTemplate。运行程序,我们看到按钮太靠近单元格的边界,所以我们给它
Margin="10"。现在,我们需要以某种方式指出顶部和底部的位置。为此,绘制一个向上箭头(但您必须做一些更漂亮的事情)。我们将从绑定角度旋转箭头:似乎就是一切。
现在我们需要设置字段的大小。
要以一种好的方式做到这一点,您需要启动另一个窗口(并且只在游戏开始时显示它),因为在游戏过程中改变场地的大小在某种程度上是错误的。但是在我们的快速原型中,我们会对此视而不见。(然后你必须重做。)
因此,我们需要有关我们有多少行和多少列的信息。我们回到虚拟机并开始上课:
为了美观,我们需要将值初始化为
BoardVM有效数字。查找和更改行:和
现在查看。向它们添加两个组合框和标签:
整体
MainWindow.xaml:现在我们需要将 VM 附加到视图。最好不要在 XAML 中,而是在
App.xaml.cs(参见此处)中执行此操作。我们写:并从 App.xaml 中删除
StartupUri。Компилируем, запускаем. Сразу видим пустое поле. Недоработка, мы ж не сгенерировали поле в конструкторе
BoardVM! Исправляем:Вот что у меня получилось: