Нажав на сетку 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 и увидеть результаты для себя.
  • Я настоятельно рекомендую вам прочитать все связанные материалы. Дайте мне знать, если вам нужна дополнительная помощь.
Другие вопросы по тегам