Martin
Martin

Reputation: 180

Clicking a Uniformgrid filled with grids, getting name of the grid im clicking

im new to WPF and im using this code to fill a uniformgrid with grids,

 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++
                    } 

im then trying to find out what name a certain grid has when i click down on the uniformedgrid called ChessBoard.

       private void ChessBoard_MouseLeftButtonDown(object sender, MouseButtonEventArgs args)
        {


            var element = (UIElement)args.Source;
            element.Opacity = 0.5; 
        }

the opacity line is test to make sure im on the right grid, and it works and changs the Opacity of the grid im clicking.

What i need help with is to find the Name attribute of the element.

Upvotes: 2

Views: 2801

Answers (1)

Fede
Fede

Reputation: 44048

Ok, delete all your code and start all over.

If you're working with WPF, you really need to understand and embrace The WPF Mentality.

As a general rule, creating or manipulating UI elements in procedural code is discouraged. Instead, you create a proper ViewModel which will hold all the relevant properties that represent the state and data shown by the UI, and use DataBinding to reflect these properties.

This is how you do what you're trying here, in 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>

Code Behind:

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);
    }
}

Data Item:

public class ChessSquare
{
    public int Row { get; set; }

    public int Column { get; set; }

    public bool IsBlack { get { return (Row + Column) %2 == 1; }}        
}

Command class (MVVM helper class):

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;
    }
}

Result:

enter image description here

  • While all this might look like "too much code", If you look closely you'll realize that most of it is actually reusable, clean code with no dependencies on the UI, and I'm also giving you a lot of reusable infrastructure (such as the Command class).

  • I'm using an ItemsControl bound to a collection of Data Items, rather than creating the UI elements procedurally. This is "letting WPF do it's job".

  • The main idea is to Separate UI and Logic, thus gaining a LOT of scalability and maintainability.
  • Notice how the code behind is reduced to a mere DataContext = .... Code behind in WPF is reserved for UI Specific code, rather than code related to data or logic.
  • I'm using a DelegateCommand to handle the Click logic, rather than an event handler. This is useful in situations where UI elements are being created dynamically by an ItemsControl and the like.
  • Also notice how the OnSquareClick() method is operating against your own simple, stateful data item (ChessSquare) rather than complex arcane WPF UI objects. That's how you program in WPF. You operate against your data, not the UI.
  • Also notice the usage of a DataTrigger against the IsBlack property, to dynamically change the background color.
  • WPF Rocks. Just copy and paste my code in a File -> New Project -> WPF Application and see the results for youself.
  • I strongly suggest you read all the linked material. Let me know if you need further help.

Upvotes: 11

Related Questions