Ok. Delete all your code and start all over.
This is how you do a Sudoku board in WPF:
XAML:
<Window x:Class="WpfApplication4.Window17"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window17" Height="300" Width="300">
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="9" Columns="9"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Row" Value="{Binding Row}"/>
<Setter Property="Grid.Column" Value="{Binding Column}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Value}" VerticalAlignment="Stretch" FontSize="20" TextAlignment="Center"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Window>
Code Behind:
using System.Collections.Generic;
using System.Windows;
using System.ComponentModel;
namespace WpfApplication4
{
public partial class Window17 : Window
{
public Window17()
{
InitializeComponent();
var random = new Random();
var board = new List<SudokuViewModel>();
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
board.Add(new SudokuViewModel() {Row = i, Column = j,Value = random.Next(1,20)});
}
}
DataContext = board;
}
}
}
ViewModel:
public class SudokuViewModel:INotifyPropertyChanged
{
public int Row { get; set; }
public int Column { get; set; }
private int _value;
public int Value
{
get { return _value; }
set
{
_value = value;
NotifyPropertyChange("Value");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChange(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
As you can see, Im in no way creating or manipulating UI elements in code. That's plain wrong in WPF. You must learn MVVM, and understand that UI is Not Data. Data is Data. UI is UI
Now, whenever you need to operate against the Value in the TextBoxes, just operate against the public int Value
property in the ViewModel. Your application logic and your UI must be completely decoupled.
Just copy and paste my code in a File -> New Project -> WPF Application
and see the results for yourself. This is how it looks in my computer:
Edit:
I have modified the sample to call a method when a Value is changed.
Please understand that you should NOT operate against the UI in WPF, but against DATA.
What you really care about is DATA (The ViewModel), not the UI itself.
using System.Collections.Generic;
using System.Windows;
using System.ComponentModel;
using System;
namespace WpfApplication4
{
public partial class Window17 : Window
{
public List<SudokuViewModel> Board { get; set; }
public Window17()
{
InitializeComponent();
var random = new Random();
Board = new List<SudokuViewModel>();
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
Board.Add(new SudokuViewModel()
{
Row = i, Column = j,
Value = random.Next(1,20),
OnValueChanged = OnItemValueChanged
});
}
}
DataContext = Board;
}
private void OnItemValueChanged(SudokuViewModel vm)
{
MessageBox.Show("Value Changed!
" + "Row: " + vm.Row + "
Column: " + vm.Column + "
Value: " + vm.Value);
}
}
public class SudokuViewModel:INotifyPropertyChanged
{
public int Row { get; set; }
public int Column { get; set; }
private int _value;
public int Value
{
get { return _value; }
set
{
_value = value;
NotifyPropertyChange("Value");
if (OnValueChanged != null)
OnValueChanged(this);
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChange(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public Action<SudokuViewModel> OnValueChanged { get; set; }
}
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…