这是我正在使用的适用于我给定情况的答案。基本上,您必须使用 VisualStateTrigger 并通过代码手动创建触发器。您可以使用各种触发器,其中许多是内置的,但在这种情况下,我不得不,或者至少我认为我必须手动编写一个。
这是触发代码。
public class StringComparisonTrigger : StateTriggerBase
{
private const string NotEqual = "NotEqual";
private const string Equal = "Equal";
public string DataValue
{
get { return (string)GetValue(DataValueProperty); }
set { SetValue(DataValueProperty, value); }
}
public static readonly DependencyProperty DataValueProperty =
DependencyProperty.Register(nameof(DataValue), typeof(string), typeof(StringComparisonTrigger), new PropertyMetadata(Equal, (s, e) =>
{
var stringComparisonTrigger = s as StringComparisonTrigger;
TriggerStateCheck(stringComparisonTrigger, stringComparisonTrigger.TriggerValue, (string)e.NewValue);
}));
public string TriggerValue
{
get { return (string)GetValue(TriggerValueProperty); }
set { SetValue(TriggerValueProperty, value); }
}
public static readonly DependencyProperty TriggerValueProperty =
DependencyProperty.Register(nameof(TriggerValue), typeof(string), typeof(StringComparisonTrigger), new PropertyMetadata(NotEqual, (s, e) =>
{
var stringComparisonTrigger = s as StringComparisonTrigger;
TriggerStateCheck(stringComparisonTrigger, stringComparisonTrigger.DataValue, (string)e.NewValue);
}));
private static void TriggerStateCheck(StringComparisonTrigger elementTypeTrigger, string dataValue, string triggerValue)
=> elementTypeTrigger.SetActive(dataValue == triggerValue);
}
这个,因为从 StateTriggerBase 继承可以在 VisualStateTriggers 组中使用,我将在下面发布。我不知道的是,您编写的任何依赖属性都可以在 XAML 中使用,并且触发器中没有接口或任何东西可以使其工作。触发触发器的唯一代码行是“SetActive(bool value)”,当您想要更改状态时必须调用它。通过在 XAML 中创建依赖属性和绑定,您可以在属性更改时触发 SetActive,从而修改视觉状态。
DataTemplate 如下。
<DataTemplate x:Key="LightsButtonTemplate">
<UserControl>
<StackPanel Name="panel">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<DataTriggers:StringComparisonTrigger DataValue="{Binding Type}"
TriggerValue="READ" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="panel.(UIElement.Background)"
Value="Red" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<TextBlock Text="{Binding Type}" />
<TextBlock Text="{Binding LightStateViewModel.On}" />
</StackPanel>
</UserControl>
</DataTemplate>
最后,您可以在任何地方使用 DataTemplate,但我在绑定到 LightViewModels 列表的 ItemsControl 中使用它。
<ScrollViewer Grid.Row="1">
<ItemsControl ItemsSource="{Binding LightViewModels}"
ItemTemplate="{StaticResource LightsButtonTemplate}" />
</ScrollViewer>
显然,这不是我想要的灯光按钮模板设计,但这是我为理解和实现动态模板所做的全部工作。希望这可以帮助来自 WPF 的其他人。
从 StateTriggerBase 派生的自定义触发器类可以按照您的意愿执行和绑定,您只需在希望更新触发器时调用 SetActive(true) 或 SetActive(false)。当它为真时,使用该触发器的 VisualState 将处于活动状态。