3 回答

TA贡献1995条经验 获得超2个赞
由于所有单元格都应具有相同的大小,因此您也可以使用UniformGrid。正如 Leo Bartkus 建议的那样,您可以使用代码隐藏来生成单元格和文本框。为此,首先在 XAML 中为数独表创建一个占位符:
<!-- Placeholder for Sudoku table (filled in code-behind) -->
<Border x:Name="SudokuTable" />
假设您使用的是Window,这是代码隐藏:
public partial class MainWindow : Window
{
private const int InnerWidth = 3;
private const int OuterWidth = InnerWidth * InnerWidth;
private const int Thin = 1;
private const int Thick = 3;
public MainWindow()
{
InitializeComponent();
InitializeViewModel();
InitializeSudokuTable();
}
public SudokuViewModel ViewModel => (SudokuViewModel)DataContext;
private void InitializeViewModel()
{
DataContext = new SudokuViewModel(OuterWidth);
}
private void InitializeSudokuTable()
{
var grid = new UniformGrid
{
Rows = OuterWidth,
Columns = OuterWidth
};
for (var i = 0; i < OuterWidth; i++)
{
for (var j = 0; j < OuterWidth; j++)
{
var border = CreateBorder(i, j);
border.Child = CreateTextBox(i, j);
grid.Children.Add(border);
}
}
SudokuTable.Child = grid;
}
private static Border CreateBorder(int i, int j)
{
var left = j % InnerWidth == 0 ? Thick : Thin;
var top = i % InnerWidth == 0 ? Thick : Thin;
var right = j == OuterWidth - 1 ? Thick : 0;
var bottom = i == OuterWidth - 1 ? Thick : 0;
return new Border
{
BorderThickness = new Thickness(left, top, right, bottom),
BorderBrush = Brushes.Black
};
}
private TextBox CreateTextBox(int i, int j)
{
var textBox = new TextBox
{
VerticalAlignment = VerticalAlignment.Center,
HorizontalAlignment = HorizontalAlignment.Center
};
var binding = new Binding
{
Source = ViewModel,
Path = new PropertyPath($"[{i},{j}]"),
Mode = BindingMode.TwoWay
};
textBox.SetBinding(TextBox.TextProperty, binding);
return textBox;
}
}
嵌套循环为 81 个单元创建每个Border和TextBox。边框的粗细是根据当前单元格的位置确定的。这将为您提供典型的数独表外观。
文本框数据绑定到视图模型的二维索引器属性。这是视图模型:
public class SudokuViewModel : ViewModelBase
{
private readonly string[,] _values;
public SudokuViewModel(int width)
{
_values = new string[width, width];
}
public string this[int i, int j]
{
get => _values[i, j];
set => Set(ref _values[i, j], value);
}
}
此索引器返回一个字符串,但您可能希望将其更改为整数并进行适当的转换和错误检查。PropertyChanged在任何情况下,它都使用 MVVM Light在索引器属性更新时引发事件。
我在这里用我的解决方案创建了一个存储库:https ://github.com/redcurry/Sudoku 。

TA贡献1936条经验 获得超6个赞
每个人的答案都很好,你的想法让我专注于一个目标:)
到目前为止,这就是我所在的位置。
XAML:我正在使用详细的 XAML 方法和网格。
网格:11x11 -(数独单元格为 9x9 + 边框为 2x2)。
<Grid Grid.Row="1" >
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition Width="2px"/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition Width="2px"/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition Height="2px"/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition Height="2px"/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Rectangle Grid.Row="0" Grid.Column="3" Grid.RowSpan="11" Fill="Black"></Rectangle>
<Rectangle Grid.Row="0" Grid.Column="7" Grid.RowSpan="11" Fill="Black"></Rectangle>
<Rectangle Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="11" Fill="Black"></Rectangle>
<Rectangle Grid.Row="7" Grid.Column="0" Grid.ColumnSpan="11" Fill="Black"></Rectangle>
<local:CellUserControl Grid.Row="0" Grid.Column="0" DataContext="{Binding Path=Cells[0], Source={StaticResource Locator}}"/>
<local:CellUserControl Grid.Row="0" Grid.Column="1" DataContext="{Binding Path=Cells[1], Source={StaticResource Locator}}"/>
...
我很懒,所以我最终使用 Excel 电子表格来枚举 81 个单元格,并使用 Floor.Math、MOD 和 Concatenate 的组合 :)
下一个挑战是将 81 MVVM 属性重构为更微不足道的东西。在 XAML 中:语法为 {Binding Path=Cells[0]} 并选择(暂时)将属性放在 ViewModelLocator 中。
public IList<CellViewModel> Cells
{
get
{
return new List<CellViewModel>(ServiceLocator.Current.GetAllInstances<CellViewModel>());
}
}
XAML 和代码是干净的。我喜欢它,到目前为止。我仍在处理 IList 的正确位置 - 它应该保留在 ViewModelLocator 中还是应该实际上在 MainViewModel 中?我想,要回答这个问题,我必须做一些单元测试。

TA贡献1834条经验 获得超8个赞
这是我如何用网格做数独的一个例子......
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="5"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="5"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBox x:Name="textBox00" TextWrapping="Wrap" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Text="1"/>
<TextBox x:Name="textBox00_Copy" TextWrapping="Wrap" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Text="1" Grid.Column="1"/>
<TextBox x:Name="textBox00_Copy1" TextWrapping="Wrap" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Text="1" Grid.Column="2"/>
<TextBox x:Name="textBox00_Copy2" TextWrapping="Wrap" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Text="1" Grid.Column="4"/>
<TextBox x:Name="textBox00_Copy3" TextWrapping="Wrap" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Text="1" Grid.Column="5"/>
<TextBox x:Name="textBox00_Copy4" TextWrapping="Wrap" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Text="1" Grid.Column="6"/>
<TextBox x:Name="textBox00_Copy5" TextWrapping="Wrap" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Text="1" Grid.Column="2" Grid.Row="1"/>
<TextBox x:Name="textBox00_Copy6" TextWrapping="Wrap" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Text="1" Grid.Column="4" Grid.Row="1"/>
<TextBox x:Name="textBox00_Copy7" TextWrapping="Wrap" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Text="1" Grid.Column="5" Grid.Row="1"/>
<TextBox x:Name="textBox00_Copy8" TextWrapping="Wrap" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Text="1" Grid.Column="1" Grid.Row="1"/>
<TextBox x:Name="textBox00_Copy9" TextWrapping="Wrap" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Text="1" Grid.Column="1" Grid.Row="2"/>
<TextBox x:Name="textBox00_Copy10" TextWrapping="Wrap" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Text="1" Grid.Column="2" Grid.Row="2"/>
<TextBox x:Name="textBox00_Copy11" TextWrapping="Wrap" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Text="1" Grid.Column="4" Grid.Row="2"/>
<Rectangle Grid.Column="3" Fill="#FF663003" Grid.RowSpan="12"/>
<Rectangle Grid.Column="7" Fill="#FF663003" Grid.RowSpan="12"/>
<Rectangle Grid.Row="3" Fill="#FF663003" Grid.ColumnSpan="12"/>
<Rectangle Grid.Row="7" Fill="#FF663003" Grid.ColumnSpan="12"/>
这只是默认的文本框样式。您可以使用用户控件使其不同,或者您可以通过在 Blend for Visual Studio 中加载 xaml 来为文本框制作自定义样式,右键单击文本框并选择编辑模板.. -> 编辑副本
- 3 回答
- 0 关注
- 117 浏览
添加回答
举报