-1

For school i have to make a WPF ui in c# the domain code is already made by the teacher. i have to handle click events on a rectangle, i chose to wrap the rectangle around a button. here is a part of my xaml where i make the rectangle

<Window x:Class="View.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:ViewModel;assembly=ViewModel"
    xmlns:controls="clr-namespace:View.Controls"
    mc:Ignorable="d"
    x:Name="Picross"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="3*"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <controls:PiCrossControl x:Name="picrossControl" Margin="0,0,10.2,-0.2" Grid="{Binding Grid}" RowConstraints="{Binding RowConstraints}" ColumnConstraints="{Binding ColumnConstraints}">
        <controls:PiCrossControl.SquareTemplate x:Uid="rect">
            <DataTemplate>
                <Button Command="{Binding Path=DataContext.OnClick, ElementName=Picross}">
                    <Rectangle IsHitTestVisible="False" Width="40" Height="40" Stroke="Black" Grid.Column="0" StrokeThickness="2">
                        <Rectangle.Fill>
                            <Binding Path="Contents.Value">
                                <Binding.Converter>
                                    <local:SquareConverter Empty="White" Filled="#123456" Unknown="Gray"/>
                                </Binding.Converter>
                            </Binding>
                        </Rectangle.Fill>
                    </Rectangle>
                </Button>
            </DataTemplate>
        </controls:PiCrossControl.SquareTemplate>
        <controls:PiCrossControl.RowConstraintsTemplate>
            <DataTemplate>
                <ItemsControl ItemsSource="{Binding Values}">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel Orientation="Horizontal" />
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Width="40" Height="40" Text="{Binding Value}" TextAlignment="Center" />
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </DataTemplate>
        </controls:PiCrossControl.RowConstraintsTemplate>
        <controls:PiCrossControl.ColumnConstraintsTemplate>
            <DataTemplate>
                <ItemsControl ItemsSource="{Binding Values}">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel Orientation="Vertical" />
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Width="40" Height="40" Text="{Binding Value}" TextAlignment="Center" />
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </DataTemplate>
        </controls:PiCrossControl.ColumnConstraintsTemplate>
    </controls:PiCrossControl>
    <Button Grid.Column="1" Width="150" Height="20" Command="{Binding CheckSolution}">
        <TextBlock Text="check solution"/>
    </Button>
</Grid>

the binding OnClick does not register for some reason. here is my datacontext of the xaml

public class GameModel
{
    private IPlayablePuzzle PlayablePuzzle;

    public GameModel()
    {
        var puzzle = Puzzle.FromRowStrings("xxxxx", "x...x", "x...x", "x...x", "xxxxx");
        var facade = new PiCrossFacade();
        this.PlayablePuzzle = facade.CreatePlayablePuzzle(puzzle);
        //Console.WriteLine(string.Join("\n", PlayablePuzzle.RowConstraints.Items.Select(x=>x.ToString())));
        //var vmGrid = this.PlayablePuzzle.Grid.Map(square => new SquareViewModel(square)).Copy();
        this.CheckSolution = new CheckSolution(PlayablePuzzle);
        this.OnClick = new OnClick();
    }
    public IGrid<IPlayablePuzzleSquare> Grid => PlayablePuzzle.Grid;
    public IEnumerable<IPlayablePuzzleConstraints> RowConstraints => this.PlayablePuzzle.RowConstraints;
    public IEnumerable<IPlayablePuzzleConstraints> ColumnConstraints => this.PlayablePuzzle.ColumnConstraints;

    public string Test => "Test";
    #region Commands 
    public ICommand CheckSolution { get; }
    public ICommand OnClick { get; }
    #endregion
}

as you can see i have 2 ICommands checksolution is also bound to a button in my xaml and that button does work (it is not wrapped around a rectangle it is just a button wrapped around a textblock) the ICommand OnClick is the one bound to my rectangle button. here is my OnClick code

public class OnClick : ICommand
{
    public event EventHandler CanExecuteChanged;

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public void Execute(object parameter)
    {
        Console.WriteLine(parameter);
    }
}

update: i set the name of window to picross and updated my binding on the button and now get the following error: System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=Picross'. BindingExpression:Path=DataContext.OnClick; DataItem=null; target element is 'Button' (Name=''); target property is 'Command' (type 'ICommand')

Rafael
  • 83
  • 3
  • 10

1 Answers1

0

This happens because the command is being bound from within a DataTemplate. You will need to "walk back" to the parent to find the data context.

Something like this:

Command="{Binding Path=DataContext.OnClick, ElementName=MainWindowName}"

In this example I am assuming you set the GameModel as the DataContext of a Window named "MainWindowName".

So you can add your name to your Window like this:

x:Name="MainWindowName"

The you can assign your data context in your window constructor like this:

    public MainWindow()
    {
      InitializeComponent();
      DataContext = new GameModel();
    }

This binding can be expressed in other ways.

Another way this can be done is using Reference like this:

Command="{Binding Path=DataContext.OnClick, Source={x:Reference picrossControl}}"
Jonathan Alfaro
  • 4,013
  • 3
  • 29
  • 32
  • i just posted my full xaml – Rafael Apr 01 '20 at 18:35
  • i added "Picross" as name of the window and when i use it in the button i get the following error System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=Picross'. BindingExpression:Path=DataContext.OnClick; DataItem=null; target element is 'Button' (Name=''); target property is 'Command' (type 'ICommand') – Rafael Apr 01 '20 at 19:50