-2

i have made an picross application in c# als my secund c# application. i am trying to keep it mvvm. but have a little problem with this.

i have an array of rectangles en when someone clicks 1 of theses rectangles the status of this one needs to be changed(color change).

i have managed to do this in a non mvvm way but really want to make is mvvm.

so the code. first the xaml code.

<Window x:Class="View.CreatePuzzle"
    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:View"
    xmlns:controls="clr-namespace:View.Controls"
    mc:Ignorable="d"
    Title="CreatePuzzle" Height="450" Width="800">
<Window.Resources>
    <VisualBrush x:Key="myBrush">
        <VisualBrush.Visual>
            <Grid>
                <Rectangle Fill="Red"/>
                <Image Source="Images/backgroundmain.jpg"/>
            </Grid>
        </VisualBrush.Visual>
    </VisualBrush>
</Window.Resources>
<Grid Background="{StaticResource myBrush}" RenderTransformOrigin="0.508,0.819" Height="450" Margin="10,0,10,0">

    <Grid.ColumnDefinitions>

        <ColumnDefinition Width="200"/>
        <ColumnDefinition Width="600"/>
    </Grid.ColumnDefinitions>

    <StackPanel>
        <TextBlock Grid.Column="0" Text="your name" />
        <TextBox Grid.Column="0" Text="{Binding Author}" />
    <TextBlock Grid.Column="0" Text="width" />
        <controls:numberinput x:Name="widthfield" Grid.Column="1"  Value="{Binding puzzlewidth}">
        </controls:numberinput>
    <TextBlock Grid.Column="0" Text="height" />
        <controls:numberinput x:Name="heightfield" Grid.Column="0" Value="{Binding puzzleheight}">
        </controls:numberinput>

        <Button Grid.Column="0" Height="25" Content="generate puzzle" 
        Command="{Binding Path=generatefield}"/>
    </StackPanel>

    <controls:PiCrossControl HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="1" x:Name="picrossControl" ColumnConstraints="{Binding ColumnConstraints}" RowConstraints="{Binding RowRonstraints }" Grid="{Binding Grid}" >
        <controls:PiCrossControl.SquareTemplate>
            <DataTemplate >
                <Rectangle Width="32" Height="32" Stroke="Black" MouseRightButtonDown="Rectangle_MouseRightButtonDown" MouseWheel="Rectangle_MouseWheel">
                    <Rectangle.InputBindings>
                        <MouseBinding Gesture="LeftClick" Command="{Binding Path=Rectangle_MouseLeftButtonDown}"/>
                    </Rectangle.InputBindings>
                    <Rectangle.Fill>
                        <Binding Path="Contents.Value"  UpdateSourceTrigger="PropertyChanged">
                            <Binding.Converter>
                                <local:SquareConverter Empty="White" Filled="Black" Unknown="green" />
                            </Binding.Converter>
                        </Binding>
                    </Rectangle.Fill>
                </Rectangle>
            </DataTemplate>
        </controls:PiCrossControl.SquareTemplate>

    </controls:PiCrossControl>
        <Button Grid.ColumnSpan="2" Height="50" Content="create puzzle" 
        Command="{Binding Path=createpuzzle}" Margin="0,340,0,0"/>
    </Grid>

here is one of the methodes is want to take out of the xaml.cs

    private void Rectangle_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
    {
        Rectangle rectangle = (Rectangle)sender;
        IPlayablePuzzleSquare square = (IPlayablePuzzleSquare)rectangle.DataContext;
       square.Contents.Value = Square.EMPTY;
    }

and the view model methode i wanna use to replace it with:

        public void Rectangle_MouseLeftButtonDown(object sender )
    {
        Debug.WriteLine("leftmousevent in vm");

    }

so when i run this code i get te following error for every rectangle :

System.Windows.Data Error: 40 : BindingExpression path error: 'Rectangle_MouseLeftButtonDown' property not found on 'object' ''PlayablePuzzleSquare' (HashCode=36468595)'. BindingExpression:Path=Rectangle_MouseLeftButtonDown; DataItem='PlayablePuzzleSquare' (HashCode=36468595); target element is 'MouseBinding' (HashCode=10961125); target property is 'Command' (type 'ICommand')

i hope someone can help me. note i am pretty new to c# but have more java experience.

thanks in advance jef uytterhoeven

2 Answers2

0

As you said; Rectangle_MouseLeftButtonDown is an event handler.

Without seeing your view-model it's hard to fix this, but, you should use the same structure as you do in the Command binding for your button:

Command="{Binding Path=generatefield}"

So, look for generatefield in your view model and duplicate and adjust it to replace the event handler.

Stefan
  • 17,448
  • 11
  • 60
  • 79
0

Since you do not wish code behind, you have to remove your Mouse left button click event handler from xaml.cs. Instead you can make use of System.Windows.Interactivity.dll . Add this reference to your project first. Then add following code in xaml . (Example)

    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseLeftButtonDown" >
            <i:InvokeCommandAction Command="{Binding MouseLeftButtonDownClick}"  >

            </i:InvokeCommandAction>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Rectangle>

As you can see in the example, my event is bound to command,which is in the View model . If you are not familiarize with EventToCommand binding , you can learn more from following link

WPF Binding UI events to commands in ViewModel

After this, you have to implement ICommand in your viewmodel . (Example)

public class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public ICommand MouseLeftButtonDownClick { get; }
        public ViewModel()
        {
            MouseLeftButtonDownClick = new RelayCommand(OnMouseLeftButtonClick);
        }

        private void OnMouseLeftButtonClick(object obj)
        {
            //Your logic on left button click
        }

        public void OnPropertyChanged(string PropName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropName));
        }
    }

I have used RelayCommand class in my viewmodel, which is nothing but ICommand implementation . If you are not familiarize with ICommand , you can learn more from following link

ICommand MVVM implementation

Praveen M
  • 443
  • 2
  • 11
  • Hi nice answer. But your command naming is conform events. You should at least address in code comments that its not proper naming. – Stefan Jul 30 '19 at 04:31