将自定义事件处理程序从View移动到ViewModel

时间:2013-11-30 13:30:29

标签: wpf events

我有一个名为OnVisualChartRangeChanged的自定义事件从名为HistoricChartControl的UserControl中触发。

我在我的主应用程序中使用这样的控件:

    Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <viewModels:HistoricViewModel/>
    </Window.DataContext>


<Grid>
    <historicChart:HistoricChartControl >
        <historicChart:HistoricChartControl 
            behaviours:ChartBehavior.OnVisualChartRangeChanged="VisualChartRangeChanged"/>
        </historicChart:HistoricChartControl>
</Grid>

我希望通过VisualChartRangeChanged方法在视图中处理事件,而不是在ViewModel中处理事件。

我怎样才能修改我的代码呢?如果您可以发布特定代码,因为我是WPF工作方式的新手,将会很有帮助。

感谢。

2 个答案:

答案 0 :(得分:1)

解决方案是使用命令。

由于它是UserControl,您可以操纵它来实现ICommandSource接口。

然后您的UserControl将能够将Command绑定到ViewModel。

一旦事件被触发,您只需调用将从ViewModel调用Execute()方法的命令。

对于WPF中的命令,我建议您阅读以下链接:

http://msdn.microsoft.com/en-us/library/ms752308(v=vs.110).aspx

在ViewModel中,您必须提供ICommand类型的属性。

编辑由于您无法操纵您的UserControl,您必须在XAML中附加命令。

交互性也是解决问题的另一种选择。看看这段代码:

 xmlns:I="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

<ListBox ...>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectionChanged">
            <i:InvokeCommandAction Command="{Binding SelectedItemChangedCommand}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</ListBox>

Interactivity是Microsoft Blend的第三方dll。

如果您在visual studio中有nuget,您将能够找到该dll。如果不是,则链接:http://www.nuget.org/packages/System.Windows.Interactivity.WPF/

答案 1 :(得分:0)

此答案已更改一次。

交互解决方案:

如果使用的行为是可重用的(您有其源),则只需将此行为的逻辑移至ViewModel级别即可。遵循这4个步骤,如果绑定和DataContext值正确,它应该有效。

  • System.Windows.InteractivityMicrosoft.Expression.Interactions的引用添加到您的项目中:

  • 在ViewModel中创建一个命令

    //ViewModel:
        public ICommand VisualChartRangeChangedCommand
        {
            get { return (ICommand)GetValue(VisualChartRangeChangedCommandProperty); }
            set { SetValue(VisualChartRangeChangedCommandProperty, value); }
        }
        public static readonly DependencyProperty VisualChartRangeChangedCommandProperty =
        DependencyProperty.Register("VisualChartRangeChangedCommand", typeof(ICommand), typeof(ViewModel), new UIPropertyMetadata(null));
    
    
    //In ViewModel constructor:
    VisualChartRangeChangedCommand = new ActionCommand(() => doStuff());
    

  • 覆盖行为并向其添加命令功能

    public class OnVisualChartRangeChangedWithCommand : OnVisualChartRangeChanged<HistoricChartControl>
    {
        //MyCommand Dependency Property
        public ICommand MyCommand
        {
            get { return (ICommand)GetValue(MyCommandProperty); }
            set { SetValue(MyCommandProperty, value); }
        }
        public static readonly DependencyProperty MyCommandProperty =
            DependencyProperty.Register("MyCommand", typeof(ICommand), typeof(OnVisualChartRangeChangedWithCommand), new UIPropertyMetadata(null));
    
        protected override void OnAttached()
        {
            //replace MouseEnter with other events related to OnVisualChartRangeChanged
            AssociatedObject.MouseEnter += _eh;
            base.OnAttached();
        }
        protected override void OnDetaching()
        {
            AssociatedObject.MouseEnter -= _eh;
            base.OnDetaching();
        }
        void _eh(object sender, MouseEventArgs e)
        {
            if (MyCommand != null)
                MyCommand.Execute(null);
        }
    }
    

  • 将ViewModel的Command链接到覆盖Behavior

    xmlns:I="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:B="clr-namespace:CoreProject.Behaviors;assembly=CoreProject"
    
    <historicChart:HistoricChartControl>
        <I:Interaction.Behaviors>
            <B:OnVisualChartRangeChangedWithCommand MyCommand="{Binding VisualChartRangeChangedCommand}"/>
        </I:Interaction.Behaviors>
    </historicChart:HistoricChartControl>