I try to use System.Windows.Interactivity to bind mouse events of elements on the screen to some command logic.
I have a simple Canvas
with three circles. A command is implemented that decreases the radius of the circles. This works fine when bound to the command property of a Button
.
Unfortunately, when I try to bind this command to the PreviewMouseDown
event of the Canvas
, it doesn't work anymore. What am I missing?
Here is the MainWindow.xaml:
<Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:test="clr-namespace:Test"
Title="MainWindow" Height="550" Width="525">
<Window.Resources>
<test:ViewModel x:Key="viewobj"/>
</Window.Resources>
<Grid>
<ItemsControl ItemsSource="{Binding CircleItems, Source={StaticResource viewobj}}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="Black" ClipToBounds="True" HorizontalAlignment="Left" Height="400" Margin="50,20,0,0" VerticalAlignment="Top" Width="400">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseDown" >
<i:InvokeCommandAction Command="{Binding StartCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding X}"/>
<Setter Property="Canvas.Top" Value="{Binding Y}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse Width="{Binding Radius}" Height="{Binding Radius}" Fill="Red"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Content="Button" Command="{Binding StartCommand, Source={StaticResource viewobj}}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="189,474,0,0"/>
</Grid>
</Window>
The MainWindow.xaml.cs is empty except for initialization in accordance to MVVM principles:
using System.Windows;
namespace Test
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
This is the ViewModel.cs:
using System.Collections.ObjectModel;
using System.ComponentModel;
using Test.Model;
namespace Test
{
public class ViewModel : INotifyPropertyChanged
{
public ObservableCollection<CircleItem> CircleItems { get; set; }
private ButtonCommand _StartCommand;
public ButtonCommand StartCommand
{
get { return _StartCommand; }
}
public ViewModel()
{
_StartCommand = new ButtonCommand(UpdateMap, () => {return true;});
CircleItems = new ObservableCollection<CircleItem>();
CircleItems.Add(new CircleItem(20, 20, 40));
CircleItems.Add(new CircleItem(60, 60, 50));
CircleItems.Add(new CircleItem(120, 100, 30));
}
public void UpdateMap()
{
CircleItem.UpdateMap(CircleItems);
}
internal void RaisePropertyChanged(string prop)
{
if (PropertyChanged != null)
{ PropertyChanged(this, new PropertyChangedEventArgs(prop)); }
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
The CircleItem.cs class:
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace Test.Model
{
public class CircleItem : INotifyPropertyChanged
{
private double _x;
public double X
{
get { return _x; }
set
{
if (_x != value)
{
_x = value;
RaisePropertyChanged("X");
}
}
}
private double _y;
public double Y
{
get { return _y; }
set
{
if (_y != value)
{
_y = value;
RaisePropertyChanged("Y");
}
}
}
private double _radius;
public double Radius
{
get { return _radius; }
set
{
if (_radius != value)
{
_radius = value;
RaisePropertyChanged("Radius");
}
}
}
public CircleItem(double x, double y, double radius)
{
this.X = x;
this.Y = y;
this.Radius = radius;
}
public static void UpdateMap(ObservableCollection<CircleItem> coll)
{
foreach (var item in coll)
{
item.Radius -= 1;
}
}
internal void RaisePropertyChanged(string prop)
{
if (PropertyChanged != null)
{ PropertyChanged(this, new PropertyChangedEventArgs(prop)); }
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
And a simple RelayCommand.cs class:
using System;
using System.Windows.Input;
namespace Test
{
public class ButtonCommand : ICommand
{
private Action WhattoExecute;
private Func<bool> WhentoExecute;
public ButtonCommand(Action What, Func<bool> When)
{
WhattoExecute = What;
WhentoExecute = When;
}
public bool CanExecute(object parameter)
{
return WhentoExecute();
}
public void Execute(object parameter)
{
WhattoExecute();
}
public event EventHandler CanExecuteChanged;
}
}
Please note that the NuGet Package "System.Windows.Interactivity v4.0 for WPF" has to be installed for this example to work.
You forgot to set the Source
of the Binding
:
<Canvas Background="Black" ClipToBounds="True" HorizontalAlignment="Left" Height="400" Margin="50,20,0,0" VerticalAlignment="Top" Width="400">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseDown">
<i:InvokeCommandAction Command="{Binding StartCommand, Source={StaticResource viewobj}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Canvas>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.