Reputation: 180
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
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:
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".
DataContext = ...
. Code behind in WPF is reserved for UI Specific code, rather than code related to data or logic.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.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.IsBlack
property, to dynamically change the background color.File -> New Project -> WPF Application
and see the results for youself.Upvotes: 11