Нажав на сетку Uniformgrid, заполненную сетками, я получаю название сетки, щелкаю
Я новичок в WPF, и я использую этот код для заполнения сетки с сетками,
public MainWindow()
{
InitializeComponent();
SolidColorBrush defaultBrush = new SolidColorBrush(Colors.Wheat);
SolidColorBrush alternateBrush = new SolidColorBrush(Colors.Black);
Char L = 'A';
int N = 1;
for (int i = 0; i < 64; i++)
{
Grid cell = new Grid();
if(N==9)
{
N=1;
L++;
}
if ((i + i / 8) % 2 == 0)
{
cell.Name = L + N.ToString();
cell.Background = defaultBrush;
ChessBoard.Children.Add(cell);
}
else
{
cell.Name = L + N.ToString();
cell.Background = alternateBrush;
ChessBoard.Children.Add(cell);
}
N++
}
Затем я пытаюсь выяснить, какое имя имеет определенная сетка, когда я нажимаю на сетку в форме ChessBoard.
private void ChessBoard_MouseLeftButtonDown(object sender, MouseButtonEventArgs args)
{
var element = (UIElement)args.Source;
element.Opacity = 0.5;
}
линия непрозрачности является тестом, чтобы убедиться, что я нахожусь на правильной сетке, и она работает и изменяет непрозрачность сетки, которую я кликаю.
Что мне нужно помочь, это найти атрибут имени элемента.
1 ответ
Хорошо, удалите весь свой код и начните все сначала.
Если вы работаете с WPF, вам действительно нужно понять и принять менталитет WPF.
Как правило, создание или управление элементами пользовательского интерфейса в процедурном коде не рекомендуется. Вместо этого вы создаете правильный ViewModel, который будет содержать все соответствующие свойства, которые представляют состояние и данные, отображаемые пользовательским интерфейсом, и используете DataBinding для отражения этих свойств.
Вот как вы делаете то, что вы пытаетесь здесь, в WPF:
<Window x:Class="ChessBoardSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="350">
<ItemsControl ItemsSource="{Binding Squares}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="8" Columns="8"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button x:Name="Square"
Command="{Binding DataContext.SquareClickCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}">
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid Background="{TemplateBinding Background}"/>
</ControlTemplate>
</Button.Template>
</Button>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsBlack}" Value="True">
<Setter TargetName="Square" Property="Background" Value="Black"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsBlack}" Value="False">
<Setter TargetName="Square" Property="Background" Value="Wheat"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Window>
Код позади:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ChessBoard();
}
}
ViewModel:
public class ChessBoard
{
public List<ChessSquare> Squares { get; private set; }
public Command<ChessSquare> SquareClickCommand { get; private set; }
public ChessBoard()
{
Squares = new List<ChessSquare>();
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
Squares.Add(new ChessSquare() {Row = i, Column = j});
}
}
SquareClickCommand = new Command<ChessSquare>(OnSquareClick);
}
private void OnSquareClick(ChessSquare square)
{
MessageBox.Show("You clicked on Row: " + square.Row + " - Column: " + square.Column);
}
}
Элемент данных:
public class ChessSquare
{
public int Row { get; set; }
public int Column { get; set; }
public bool IsBlack { get { return (Row + Column) %2 == 1; }}
}
Командный класс (вспомогательный класс MVVM):
public class Command<T>: ICommand
{
public Action<T> Action { get; set; }
public void Execute(object parameter)
{
if (Action != null && parameter is T)
Action((T)parameter);
}
public bool CanExecute(object parameter)
{
return IsEnabled;
}
private bool _isEnabled = true;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}
}
public event EventHandler CanExecuteChanged;
public Command(Action<T> action)
{
Action = action;
}
}
Результат:
Хотя все это может выглядеть как "слишком много кода", если вы внимательно посмотрите, вы поймете, что большая его часть на самом деле является многоразовым, чистый код без каких-либо зависимостей от пользовательского интерфейса, и я также даю вам много повторно используемой инфраструктуры (такой как
Command
учебный класс).Я использую
ItemsControl
связаны с коллекцией элементов данных, а не с процедурным созданием элементов пользовательского интерфейса. Это "позволить WPF делать свою работу".- Основная идея состоит в том, чтобы разделить пользовательский интерфейс и логику, таким образом, получая МНОГО масштабируемости и удобства обслуживания.
- Обратите внимание, что код позади сводится к простому
DataContext = ...
, Код позади в WPF зарезервирован для конкретного кода пользовательского интерфейса, а не кода, связанного с данными или логикой. - Я использую
DelegateCommand
обрабатывать логику Click, а не обработчик событий. Это полезно в ситуациях, когда элементы пользовательского интерфейса создаются динамически с помощью ItemsControl и т.п. - Также обратите внимание, как
OnSquareClick()
метод работает с вашим собственным простым элементом данных с состоянием (ChessSquare
), а не сложные загадочные объекты пользовательского интерфейса WPF. Вот как вы программируете в WPF. Вы оперируете своими данными, а не пользовательским интерфейсом. - Также обратите внимание на использование DataTrigger против
IsBlack
свойство, для динамического изменения цвета фона. - WPF Rocks. Просто скопируйте и вставьте мой код в
File -> New Project -> WPF Application
и увидеть результаты для себя. - Я настоятельно рекомендую вам прочитать все связанные материалы. Дайте мне знать, если вам нужна дополнительная помощь.