我修改了 Neutrino 的解决方案,使 xaml 在指定值时看起来不那么冗长:
抱歉没有渲染 xaml 的图片,想象一下您单击的 [=] 汉堡按钮,它变成 [<-] 后退按钮并切换网格的可见性。
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
...
<Grid>
<Button x:Name="optionsButton">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<local:SetterAction PropertyName="Visibility" Value="Collapsed" />
<local:SetterAction PropertyName="Visibility" TargetObject="{Binding ElementName=optionsBackButton}" Value="Visible" />
<local:SetterAction PropertyName="Visibility" TargetObject="{Binding ElementName=optionsPanel}" Value="Visible" />
</i:EventTrigger>
</i:Interaction.Triggers>
<glyphs:Hamburger Width="10" Height="10" />
</Button>
<Button x:Name="optionsBackButton" Visibility="Collapsed">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<local:SetterAction PropertyName="Visibility" Value="Collapsed" />
<local:SetterAction PropertyName="Visibility" TargetObject="{Binding ElementName=optionsButton}" Value="Visible" />
<local:SetterAction PropertyName="Visibility" TargetObject="{Binding ElementName=optionsPanel}" Value="Collapsed" />
</i:EventTrigger>
</i:Interaction.Triggers>
<glyphs:Back Width="12" Height="11" />
</Button>
</Grid>
...
<Grid Grid.RowSpan="2" x:Name="optionsPanel" Visibility="Collapsed">
</Grid>
您也可以像在 Neutrino 的解决方案中那样指定值:
<Button x:Name="optionsButton">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<local:SetterAction PropertyName="Visibility" Value="{x:Static Visibility.Collapsed}" />
<local:SetterAction PropertyName="Visibility" TargetObject="{Binding ElementName=optionsBackButton}" Value="{x:Static Visibility.Visible}" />
<local:SetterAction PropertyName="Visibility" TargetObject="{Binding ElementName=optionsPanel}" Value="{x:Static Visibility.Visible}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<glyphs:Hamburger Width="10" Height="10" />
</Button>
这是代码。
using System;
using System.ComponentModel;
using System.Reflection;
using System.Windows;
using System.Windows.Interactivity;
namespace Mvvm.Actions
{
/// <summary>
/// Sets a specified property to a value when invoked.
/// </summary>
public class SetterAction : TargetedTriggerAction<FrameworkElement>
{
#region Properties
#region PropertyName
/// <summary>
/// Property that is being set by this setter.
/// </summary>
public string PropertyName
{
get { return (string)GetValue(PropertyNameProperty); }
set { SetValue(PropertyNameProperty, value); }
}
public static readonly DependencyProperty PropertyNameProperty =
DependencyProperty.Register("PropertyName", typeof(string), typeof(SetterAction),
new PropertyMetadata(String.Empty));
#endregion
#region Value
/// <summary>
/// Property value that is being set by this setter.
/// </summary>
public object Value
{
get { return (object)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(SetterAction),
new PropertyMetadata(null));
#endregion
#endregion
#region Overrides
protected override void Invoke(object parameter)
{
var target = TargetObject ?? AssociatedObject;
var targetType = target.GetType();
var property = targetType.GetProperty(PropertyName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
if (property == null)
throw new ArgumentException(String.Format("Property not found: {0}", PropertyName));
if (property.CanWrite == false)
throw new ArgumentException(String.Format("Property is not settable: {0}", PropertyName));
object convertedValue;
if (Value == null)
convertedValue = null;
else
{
var valueType = Value.GetType();
var propertyType = property.PropertyType;
if (valueType == propertyType)
convertedValue = Value;
else
{
var propertyConverter = TypeDescriptor.GetConverter(propertyType);
if (propertyConverter.CanConvertFrom(valueType))
convertedValue = propertyConverter.ConvertFrom(Value);
else if (valueType.IsSubclassOf(propertyType))
convertedValue = Value;
else
throw new ArgumentException(String.Format("Cannot convert type '{0}' to '{1}'.", valueType, propertyType));
}
}
property.SetValue(target, convertedValue);
}
#endregion
}
}
编辑:Interactivity dll 不再是 Blend 的一部分,现在是“Microsoft.Xaml.Behaviors.Wpf”NuGet 包。此处列出的代码:https ://github.com/microsoft/XamlBehaviorsWpf
请参阅:https ://devblogs.microsoft.com/dotnet/open-sourcing-xaml-behaviors-for-wpf/
从旧的 Blend Microsoft.Expression.Interactions.dll 迁移到新的开源交互 dll 的步骤(希望我的旧笔记是正确的;p):
1. Install the "Microsoft.Xaml.Behaviors.Wpf" NuGet package.
2. Edit xaml files:
Replace 'http://schemas.microsoft.com/expression/2010/interactivity' and
'http://schemas.microsoft.com/expression/2010/interactions'
with 'http://schemas.microsoft.com/xaml/behaviors'.
Replace 'xmlns:ei="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"' and
'xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"'
with 'xmlns:i="http://schemas.microsoft.com/xaml/behaviors"'.
3. Edit C# files:
Replace usings in c# files 'Microsoft.Xaml.Interactivity' and
'Microsoft.Xaml.Interactions'
with 'Microsoft.Xaml.Behaviors'.
Remove references to 'Microsoft.Expression.Interactions' and
'System.Windows.Interactivity'.