在視圖模型上顯示多個視圖的WPF-MVVM應用程序。用戶可以在運行時從較不詳細的視圖轉到更詳細的視圖。視圖包含在邊框內。在一組條件下,警報由視圖模型觸發。警報在邊界背景上呈現爲閃爍顏色的動畫,以吸引用戶注意。這個MultiDataTrigger爲什麼會在動畫中引發異常?
問題是,當觸發警報並且用戶在運行時更改數據模板以獲取更多詳細信息時,WPF引擎在使用多數據觸發器警報時會引發動畫異常。引擎在使用Datatrigger時工作,在MultiDataTrigger上崩潰並且其他所有內容都相同。
例外情況是:不能動畫不可變對象
的示例應用程序來演示問題上 '(0)(1)':
1主窗口用於託管和切換視圖。
2意見,大和小。
1 viewmodel。
1個資源字典用於多和單datatriggers
App.xaml中:
<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();
}
}
}
SampleViewMo del.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;
}
}
}
Dictionary1.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>
SmallUserControl.xaml:
<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>
如果您運行的代碼,點擊鬧鐘並閃爍eckboxes,那麼控件將從黑色背景的銀色邊框變成閃爍的橙色。如果您將滑塊從小到大的視圖移動,如果使用多數據觸發器,您將從wpf獲得運行時間。如果您取消註釋Dictionar1.xaml中的數據觸發器並評論多數據觸發器,然後重複上述操作,則應用程序運行正常。
爲什麼這個multidatatrigger在DataTemplate變化和datatrigger工作正常嗎?唯一的區別是單個數據觸發器是一個額外的布爾值。它如何被修復?
(是的,可以通過在viewmodel上創建一個屬性來對這些布爾值進行聚合,但是這不應該被完成,並且不存在問題,這看起來像是一個wpf錯誤?)
什麼是例外? – Mishka
不能在不可變對象上動畫'(0)。(1)' –