C# 为什么这个MultiDataTrigger会在动画上引发异常?
在viewmodel上显示多个视图的WPF-MVVM应用程序。用户可以在运行时从不太详细的视图转到更详细的视图。视图包含在边框内。在一组条件下,viewmodel会触发报警。报警在视图中呈现为边框背景上闪烁颜色的动画,以吸引用户注意 问题在于,当触发报警并且用户在运行时更改数据模板以获取更多细节时,WPF引擎在使用multidatatrigger报警时会在动画上引发异常。引擎在使用Datatrigger时工作,在其他一切相同的情况下在MultiDataTrigger上崩溃 例外情况是:无法在不可变对象上设置“(0)。(1)”的动画 演示问题的示例应用程序: 1个用于承载和切换视图的主窗口 2个视图,大视图和小视图 1视图模型 1个用于多个和单个datatriggers的资源字典 App.Xaml:C# 为什么这个MultiDataTrigger会在动画上引发异常?,c#,wpf,mvvm,C#,Wpf,Mvvm,在viewmodel上显示多个视图的WPF-MVVM应用程序。用户可以在运行时从不太详细的视图转到更详细的视图。视图包含在边框内。在一组条件下,viewmodel会触发报警。报警在视图中呈现为边框背景上闪烁颜色的动画,以吸引用户注意 问题在于,当触发报警并且用户在运行时更改数据模板以获取更多细节时,WPF引擎在使用multidatatrigger报警时会在动画上引发异常。引擎在使用Datatrigger时工作,在其他一切相同的情况下在MultiDataTrigger上崩溃 例外情况是:无法在不可
<Application x:Class="AnimationSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:AnimationSample"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary Source="Dictionary1.xaml"/>
</Application.Resources>
</Application>
MainWindow.xaml:
<Window x:Class="AnimationSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:AnimationSample"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type local:SampleViewModel}" x:Key="smallTemplate">
<local:SmallUserControl />
</DataTemplate>
<DataTemplate DataType="{x:Type local:SampleViewModel}" x:Key="largeTemplate">
<local:LargeUserControl />
</DataTemplate>
<DataTemplate DataType="{x:Type local:SampleViewModel}" x:Key="mainTemplate">
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding ElementName=ZoomSlider, Path=Value}" Value="1">
<Setter Property="ContentTemplate" Value="{StaticResource smallTemplate}"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=ZoomSlider, Path=Value}" Value="2">
<Setter Property="ContentTemplate" Value="{StaticResource largeTemplate}"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
<Style TargetType="{x:Type ContentControl}" x:Key="DisplayStyle">
<Setter Property="ContentTemplate" Value="{StaticResource smallTemplate}" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ZoomSlider, Path=Value}" Value="1">
<Setter Property="ContentTemplate" Value="{StaticResource smallTemplate}"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=ZoomSlider, Path=Value}" Value="2">
<Setter Property="ContentTemplate" Value="{StaticResource largeTemplate}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel Margin="8">
<Slider x:Name="ZoomSlider" Minimum="1" Maximum="2" IsSnapToTickEnabled="True" />
<ContentControl Content="{Binding}" Style="{StaticResource DisplayStyle}">
</ContentControl>
</StackPanel>
</Window>
MainWindow.cs:
using System.Windows;
namespace AnimationSample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new SampleViewModel();
}
}
}
使用System.Windows;
名称空间动画示例
{
///
///MainWindow.xaml的交互逻辑
///
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
DataContext=新的SampleViewModel();
}
}
}
SampleViewModel.cs:
using System;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Windows;
namespace AnimationSample
{
public class SampleViewModel : NotifyPropertyChangedBase<SampleViewModel>
{
private bool _alarm;
public bool Alarm
{
get { return _alarm; }
set
{
if (!_alarm.Equals(value))
{
_alarm = value;
OnPropertyChanged("Alarm");
}
}
}
private bool _flash;
public bool Flash
{
get { return _flash; }
set
{
if (!_flash.Equals(value))
{
_flash = value;
OnPropertyChanged("Flash");
}
}
}
private string _description = "I am an alarm!";
public string Description
{
get { return _description; }
set
{
if(!_description.Equals(value))
{
_description = value;
OnPropertyChanged("Description");
}
}
}
}
public abstract class NotifyPropertyChangedBase<T> : DependencyObject, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{ PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName)); }
}
protected virtual void OnPropertyChanged<T2>(Expression<Func<T, T2>> accessor)
{
OnPropertyChanged(PropertyName(accessor));
}
public static string PropertyName<T2>(Expression<Func<T, T2>> accessor)
{
return ((MemberExpression)accessor.Body).Member.Name;
}
}
}
使用系统;
使用系统组件模型;
使用System.Linq.Expressions;
使用System.Windows;
名称空间动画示例
{
公共类SampleViewModel:NotifyPropertyChangedBase
{
私家车报警;
公共报警
{
获取{return\u alarm;}
设置
{
如果(!\u报警等于(值))
{
_报警=数值;
不动产变更(“报警”);
}
}
}
私人布卢闪光灯;
公共广播闪光灯
{
获取{return\u flash;}
设置
{
如果(!\u flash.Equals(值))
{
_闪光=数值;
OnPropertyChanged(“Flash”);
}
}
}
私有字符串_description=“我是警报!”;
公共字符串描述
{
获取{return\u description;}
设置
{
如果(!\u说明等于(值))
{
_描述=值;
不动产变更(“说明”);
}
}
}
}
公共抽象类NotifyPropertyChangedBase:DependencyObject,INotifyPropertyChanged
{
公共事件属性更改事件处理程序属性更改;
受保护的虚拟void OnPropertyChanged(字符串propertyName)
{
if(PropertyChanged!=null)
{PropertyChanged.Invoke(这是新的PropertyChangedEventArgs(propertyName));}
}
受保护的虚拟void OnPropertyChanged(表达式访问器)
{
OnPropertyChanged(PropertyName(访问器));
}
公共静态字符串PropertyName(表达式访问器)
{
返回((MemberExpression)accessor.Body).Member.Name;
}
}
}
字典1.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:AnimationSample">
<Style x:Key="FlashyAlarmBorderStyle" TargetType="{x:Type Border}">
<Setter Property="BorderBrush" Value="Silver"/>
<Setter Property="Background" Value="Black" />
<Setter Property="BorderThickness" Value="2" />
<Setter Property="CornerRadius" Value="8" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Alarm}" Value="True" />
<Condition Binding="{Binding Flash}" Value="True" />
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="Orange"/>
<Setter Property="BorderBrush" Value="Orange"/>
<MultiDataTrigger.EnterActions>
<BeginStoryboard Name="faultBoard">
<Storyboard>
<ColorAnimation AutoReverse="True"
RepeatBehavior="Forever"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
Duration="00:00:01"
From="Silver"
To="Orange"/>
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
<MultiDataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="faultBoard">
</StopStoryboard>
</MultiDataTrigger.ExitActions>
</MultiDataTrigger>
<!--<DataTrigger Binding="{Binding Alarm}" Value="True" >
<Setter Property="Background" Value="Orange"/>
<Setter Property="BorderBrush" Value="Orange"/>
<DataTrigger.EnterActions>
<BeginStoryboard Name="alarmBoard">
<Storyboard>
<ColorAnimation AutoReverse="True"
RepeatBehavior="Forever"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
Duration="00:00:01"
From="Silver"
To="Orange"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="alarmBoard">
</StopStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>-->
</Style.Triggers>
</Style>
</ResourceDictionary>
LargeUserControl.xaml:
<UserControl x:Class="AnimationSample.LargeUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:AnimationSample"
mc:Ignorable="d" >
<Border Margin="8"
Style="{DynamicResource FlashyAlarmBorderStyle}">
<StackPanel>
<Label HorizontalAlignment="Center" Content="LARGE VIEW" Foreground="White"/>
<CheckBox Margin="8" IsChecked="{Binding Alarm}" Content="Turn on the alarm." Foreground="White" />
<CheckBox Margin="8" IsChecked="{Binding Flash}" Content="Turn on the flash!" Foreground="White" />
<Label Margin="8" Content="{Binding Description}" Foreground="White"/>
</StackPanel>
</Border>
</UserControl>
<UserControl x:Class="AnimationSample.SmallUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:AnimationSample"
mc:Ignorable="d" >
<Border Margin="8"
Style="{DynamicResource FlashyAlarmBorderStyle}">
<StackPanel>
<Label HorizontalAlignment="Center" Content="SMALL VIEW" Foreground="White"/>
<CheckBox Margin="4" IsChecked="{Binding Alarm}" Content="Turn on the alarm." HorizontalAlignment="Center" Foreground="White" />
<CheckBox Margin="4" IsChecked="{Binding Flash}" Content="Turn on the flash!" HorizontalAlignment="Center" Foreground="White" />
</StackPanel>
</Border>
</UserControl>
SmallUserControl.xaml:
<UserControl x:Class="AnimationSample.LargeUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:AnimationSample"
mc:Ignorable="d" >
<Border Margin="8"
Style="{DynamicResource FlashyAlarmBorderStyle}">
<StackPanel>
<Label HorizontalAlignment="Center" Content="LARGE VIEW" Foreground="White"/>
<CheckBox Margin="8" IsChecked="{Binding Alarm}" Content="Turn on the alarm." Foreground="White" />
<CheckBox Margin="8" IsChecked="{Binding Flash}" Content="Turn on the flash!" Foreground="White" />
<Label Margin="8" Content="{Binding Description}" Foreground="White"/>
</StackPanel>
</Border>
</UserControl>
<UserControl x:Class="AnimationSample.SmallUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:AnimationSample"
mc:Ignorable="d" >
<Border Margin="8"
Style="{DynamicResource FlashyAlarmBorderStyle}">
<StackPanel>
<Label HorizontalAlignment="Center" Content="SMALL VIEW" Foreground="White"/>
<CheckBox Margin="4" IsChecked="{Binding Alarm}" Content="Turn on the alarm." HorizontalAlignment="Center" Foreground="White" />
<CheckBox Margin="4" IsChecked="{Binding Flash}" Content="Turn on the flash!" HorizontalAlignment="Center" Foreground="White" />
</StackPanel>
</Border>
</UserControl>
如果运行代码并单击报警和闪烁复选框,则控件将从黑色背景的银色边框变为闪烁的橙色。如果将滑块从小视图移动到大视图,则如果使用multidatatrigger,将从wpf获得运行时。如果在Dictionar1.xaml中取消对datatrigger的注释,并对multidatatrigger进行注释,然后重复上述操作,则应用程序运行正常
为什么DataTemplate上的multidatatrigger gag发生了变化,datatrigger工作正常?与单个datatrigger的唯一区别是增加了一个布尔值。怎么能修好呢
(是的,可以通过在viewmodel上创建一个属性来聚合这些布尔值来解决问题,但这不必这样做,也不存在问题。这似乎是wpf的一个bug?删除设置与您尝试设置动画的相同属性(
背景
)的setter:
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Alarm}" Value="True" />
<Condition Binding="{Binding Flash}" Value="True" />
</MultiDataTrigger.Conditions>
<!--<Setter Property="Background" Value="Orange"/>-->
<Setter Property="BorderBrush" Value="Orange"/>
<MultiDataTrigger.EnterActions>
<BeginStoryboard Name="faultBoard">
<Storyboard>
<ColorAnimation AutoReverse="True"
RepeatBehavior="Forever"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
Duration="00:00:01"
From="Silver"
To="Orange"/>
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
<MultiDataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="faultBoard">
</StopStoryboard>
</MultiDataTrigger.ExitActions>
</MultiDataTrigger>
有什么例外?无法在不可变对象上设置“(0)。(1)”的动画。这对我来说是正确的!不知道我抽的是什么…谢谢你的评论!