Привязка к событию мыши в wpf mvvm

Я пытаюсь использовать System.Windows.Interactivity, чтобы связать события мыши элементов на экране с некоторой логикой команд.

У меня простой Canvas с тремя кружками. Реализована команда, уменьшающая радиус окружностей. Это отлично работает при привязке к свойству command Button.

К сожалению, когда я пытаюсь привязать эту команду к событию PreviewMouseDownCanvas, она больше не работает. Что мне не хватает?

Вот файл 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>

MainWindow.xaml.cs пуст, за исключением инициализации в соответствии с принципами MVVM:

using System.Windows;

namespace Test
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

Это 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;
    }
}

Класс CircleItem.cs:

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

И простой класс RelayCommand.cs:

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

Обратите внимание, что для работы этого примера необходимо установить пакет NuGet «System.Windows.Interactivity v4.0 for WPF».

Потому что вы ищете StartCommand в CircleItem, поскольку ваши элементы привязаны к коллекции CircleItems

Evertude 10.08.2018 14:53
1
1
2 067
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы забыли установить Source из 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>

О, какая глупая ошибка. У меня все еще есть проблемы с отладкой таких ошибок, поскольку они не оставляют следов в окне вывода, и я не могу установить точку останова, чтобы узнать, что происходит ...

Thern 18.08.2018 13:44

Другие вопросы по теме