行为库

ChangePropertyAction

这是一个可以修改属性值的动作。当生效后,它会在后台借助反射的方式找到想要修改的属性,并为它赋新值。要操控的对象可以是一个控件,也可以是一个视图模型。

基本用法

我们可以借助这个动作实现对于窗口状态(最大化、最小化等)的操作,例如:

<Window x:Name="window">
    <!-- 最大化按钮 -->
    <Button Content="Maximize">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="Click">
                <i:ChangePropertyAction PropertyName="WindowState" Value="Maximized" TargetObject="{Binding ElementName=window}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Button>
    <!-- 最小化按钮 -->
    <Button Content="Minimize">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="Click">
                <i:ChangePropertyAction PropertyName="WindowState" Value="Minimized" TargetObject="{Binding ElementName=window}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Button>
</Window>

它们所做的事情就好比在后台执行了下面的代码:

window.WindowState = WindowState.Maximized;
window.WindowState = WindowState.Minimized;

这样的技巧在 MVVM 中是非常常见的。因为这里我们希望按钮的功能是操作界面,但视图模型中并不应该包含任何 UI 相关的逻辑,这会导致我们可能被迫要在视图的后台代码中实现一些 UI 相关的逻辑。借助触发器和动作,我们就可以将这些简单的逻辑在前台 XAML 代码中快速实现。

错误案例

虽然确实可以借助 ChangePropertyAction 来修改视图模型的某个属性,但通常我们并不会这样做,而是会分析要做的事情本质上是要实现什么功能,然后选择更合适的方式,比如借助属性绑定等来实现。

一个经典的错误例子是,使用 EventTrigger 订阅一个 CheckBoxCheckedUnchecked 事件,然后在事件触发后使用 ChangePropertyAction 来修改一个属性(比如另一个控件的 Visibility)。实际上,我们可以直接将 CheckBoxIsChecked 属性绑定到相应属性上(可能需要辅助以值转换器),这样就不需要使用 ChangePropertyAction 了。

<CheckBox>
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="Checked">
      <i:ChangePropertyAction PropertyName="Visibility"
                              Value="Visible"
                              TargetObject="{Binding ElementName=button}" />
    </i:EventTrigger>
    <i:EventTrigger EventName="Unchecked">
      <i:ChangePropertyAction PropertyName="Visibility"
                              Value="Collapsed"
                              TargetObject="{Binding}" />
    </i:EventTrigger>
  </i:Interaction.Triggers>
</CheckBox>
 
<Button x:Name="button" Content="Click Me" />

类似的错误例子还比如对 ExpanderComboBox 等控件的一些操作。正确的做法是设法绑定它们的 IsExpandedSelectedItem 等属性到视图模型的属性上。

修改附加属性的值

原生的 ChangePropertyAction 只能修改依赖属性的值,但我们也可以自定义一个 ChangeAttachedPropertyAction 来修改附加属性的值。这里有一个简单的实现:

GitHub Gist - ChangeAttachedPropertyAction.cs

On this page