100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > c# WPF中System.Windows.Interactivity的使用

c# WPF中System.Windows.Interactivity的使用

时间:2020-01-16 21:02:50

相关推荐

c# WPF中System.Windows.Interactivity的使用

背景

在我们进行WPF开发应用程序的时候不可避免的要使用到事件,很多时候没有严格按照MVVM模式进行开发的时候习惯直接在xaml中定义事件,然后再在对应的.cs文件中直接写事件的处理过程,这种处理方式写起来非常简单而且不用过多地处理考虑代码之c#教程间是否符合规范,但是我们在写代码的时候如果完全按照WPF规范的MVVM模式进行开发的时候就应该将相应的事件处理写在ViewModel层,这样整个代码才更加符合规范而且层次也更加清楚,更加符合MVVM规范。

常规用法

1 引入命名空间

通过在代码中引入System.Windows.Interactivity.dll,引入了这个dll后我们就能够使用这个里面的方法来将事件映射到ViewModel层了,我们来看看具体的使用步骤,第一步就是引入命名控件

1

xmlns:i=“clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity”

另外还可以通过另外一种方式来引入命名空间,其实这两者间都是对等的。

1

xmlns:i=/expression//interactivity

2 添加事件对应的Command

这里以TextBox的GetFocus和LostFocus为例来进行说明

<TextBox Text="CommandBinding"><i:Interaction.Triggers><i:EventTrigger EventName="LostFocus"><i:InvokeCommandAction Command="{Binding OnTextLostFocus}"CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType={x:Type TextBox}}}"/></i:EventTrigger><i:EventTrigger EventName="GotFocus"><i:InvokeCommandAction Command="{Binding OnTextGotFocus}"CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType={x:Type TextBox}}}"/></i:EventTrigger></i:Interaction.Triggers></TextBox>

这个里面我们重点来看看这个InvokeCommandAction的代码结构

namespace System.Windows.Interactivity{public sealed class InvokeCommandAction : TriggerAction<DependencyObject>{public static readonly DependencyProperty CommandProperty;public static readonly DependencyProperty CommandParameterProperty;public InvokeCommandAction();public string CommandName {get; set; }public ICommand Command {get; set; }public object CommandParameter {get; set; }protected override void Invoke(object parameter);}}

这里我们发现这里我们如果我们定义一个Command的话我们只能够在Command中获取到我们绑定的CommandParameter这个参数,但是有时候我们需要获取到触发这个事件的RoutedEventArgs的时候,通过这种方式就很难获取到了,这个时候我们就需要自己去扩展一个InvokeCommandAction了,这个时候我们应该怎么做呢?整个过程分成三步:

2.1 定义自己的CommandParameter

public class ExCommandParameter{/// <summary> /// 事件触发源 /// </summary> public DependencyObject Sender {get; set; }/// <summary> /// 事件参数 /// </summary> public EventArgs EventArgs {get; set; }/// <summary> /// 额外参数 /// </summary> public object Parameter {get; set; }}

这个对象除了封装我们常规的参数外还封装了我们需要的EventArgs属性,有了这个我们就能将当前的事件的EventArgs传递进来了。

2.2 重写自己的InvokeCommandAction

public class ExInvokeCommandAction : TriggerAction<DependencyObject>{private string commandName;public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(ExInvokeCommandAction), null);public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(ExInvokeCommandAction), null);/// <summary> /// 获得或设置此操作应调用的命令的名称。 /// </summary> /// <value>此操作应调用的命令的名称。</value> /// <remarks>如果设置了此属性和 Command 属性,则此属性将被后者所取代。</remarks> public string CommandName{get{base.ReadPreamble();return mandName;}set{if (mandName != value){base.WritePreamble();mandName = value;base.WritePostscript();}}}/// <summary> /// 获取或设置此操作应调用的命令。这是依赖属性。 /// </summary> /// <value>要执行的命令。</value> /// <remarks>如果设置了此属性和 CommandName 属性,则此属性将优先于后者。</remarks> public ICommand Command{get{return (ICommand)base.GetValue(mandProperty);}set{base.SetValue(mandProperty, value);}}/// <summary> /// 获得或设置命令参数。这是依赖属性。 /// </summary> /// <value>命令参数。</value> /// <remarks>这是传递给 ICommand.CanExecute 和 ICommand.Execute 的值。</remarks> public object CommandParameter{get{return base.GetValue(mandParameterProperty);}set{base.SetValue(mandParameterProperty, value);}}/// <summary> /// 调用操作。 /// </summary> /// <param name="parameter">操作的参数。如果操作不需要参数,则可以将参数设置为空引用。</param> protected override void Invoke(object parameter){if (base.AssociatedObject != null){ICommand command = this.ResolveCommand();/** ★★★★★★★★★★★★★★★★★★★★★★★★* 注意这里添加了事件触发源和事件参数* ★★★★★★★★★★★★★★★★★★★★★★★★*/ExCommandParameter exParameter = new ExCommandParameter{Sender = base.AssociatedObject,Parameter = GetValue(CommandParameterProperty),EventArgs = parameter as EventArgs};if (command != null && command.CanExecute(exParameter)){/** ★★★★★★★★★★★★★★★★★★★★★★★★* 注意将扩展的参数传递到Execute方法中* ★★★★★★★★★★★★★★★★★★★★★★★★*/command.Execute(exParameter);}}}private ICommand ResolveCommand(){ICommand result = null;if (mand != null){result = mand;}else{if (base.AssociatedObject != null){Type type = base.AssociatedObject.GetType();PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);PropertyInfo[] array = properties;for (int i = 0; i < array.Length; i++){PropertyInfo propertyInfo = array[i];if (typeof(ICommand).IsAssignableFrom(propertyInfo.PropertyType) && string.Equals(propertyInfo.Name, mandName, StringComparison.Ordinal)){result = (ICommand)propertyInfo.GetValue(base.AssociatedObject, null);}}}}return result;}}

这个里面的重点是要重写基类中的Invoke方法,将当前命令通过反射的方式来获取到,然后在执行command.Execute方法的时候将我们自定义的ExCommandParameter传递进去,这样我们就能够在最终绑定的命令中获取到特定的EventArgs对象了。

2.3 在代码中应用自定义InvokeCommandAction

<ListBox x:Name="lb_selecthistorymembers"SnapsToDevicePixels="true"ItemsSource="{Binding DataContext.SpecificHistoryMembers,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=my:AnnouncementApp},Mode=TwoWay}"HorizontalAlignment="Stretch"ScrollViewer.HorizontalScrollBarVisibility="Disabled"Background="#fff"BorderThickness="1"><i:Interaction.Triggers><i:EventTrigger EventName="SelectionChanged"><interactive:ExInvokeCommandAction Command="{Binding DataContext.OnSelectHistoryMembersListBoxSelected,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=my:AnnouncementApp},Mode=TwoWay}"CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBox}}"></interactive:ExInvokeCommandAction></i:EventTrigger></i:Interaction.Triggers> </ListBox>

注意这里需要首先引入自定义的interactive的命名空间,这个在使用的时候需要注意,另外在最终的Command订阅中EventArgs根据不同的事件有不同的表现形式,比如Loaded事件,那么最终获取到的EventArgs就是RoutedEventArgs对象,如果是TableControl的SelectionChanged事件,那么最终获取到的就是SelectionChangedEventArgs对象,这个在使用的时候需要加以区分。

3 使用当前程序集增加Behavior扩展

System.Windows.Interactivity.dll中一个重要的扩展就是对Behavior的扩展,这个Behavior到底该怎么用呢?我们来看下面的一个例子,我们需要给一个TextBlock和Button增加一个统一的DropShadowEffect,我们先来看看最终的效果,然后再就具体的代码进行分析。

代码分析

1 增加一个EffectBehavior

public class EffectBehavior : Behavior<FrameworkElement>{protected override void OnAttached(){base.OnAttached();AssociatedObject.MouseEnter += AssociatedObject_MouseEnter;AssociatedObject.MouseLeave += AssociatedObject_MouseLeave;}private void AssociatedObject_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e){var element = sender as FrameworkElement;element.Effect = new DropShadowEffect() {Color = Colors.Transparent, ShadowDepth = 2 }; ;}private void AssociatedObject_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e){var element = sender as FrameworkElement;element.Effect = new DropShadowEffect() {Color = Colors.Red, ShadowDepth = 2 };}protected override void OnDetaching(){base.OnDetaching();AssociatedObject.MouseEnter -= AssociatedObject_MouseEnter;AssociatedObject.MouseLeave -= AssociatedObject_MouseLeave;}}

这里我们继承自System.Windows.Interactivity中的Behavior这个泛型类,这里我们的泛型参数使用FrameworkElement,因为大部分的控件都是继承自这个对象,我们方便为其统一添加效果,在集成这个基类后我们需要重写基类的OnAttached和OnDetaching方法,这个里面AssociatedObject就是我们具体添加Effect的元素,在我们的示例中这个分别是TextBlock和Button对象。

2 在具体的控件中添加此效果

<Window x:Class="WpfBehavior.MainWindow"xmlns="/winfx//xaml/presentation"xmlns:x="/winfx//xaml"xmlns:d="/expression/blend/"xmlns:mc="/markup-compatibility/"xmlns:local="clr-namespace:WpfBehavior"xmlns:i="/expression//interactivity"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"><Grid><StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center"><TextBlock Text="测试文本" Margin="2" Height="30"><i:Interaction.Behaviors><local:EffectBehavior></local:EffectBehavior></i:Interaction.Behaviors></TextBlock><Button Content="测试" Width="80" Height="30" Margin="2"><i:Interaction.Behaviors><local:EffectBehavior></local:EffectBehavior></i:Interaction.Behaviors></Button></StackPanel></Grid></Window>

以上就是c# WPF中System.Windows.Interactivity的使用的详细内容

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。