ビューモデルに複数のビューを表示するWPF-MVVMアプリケーション。実行時に、より詳細なビューからより詳細なビューに移動することができます。ビューは境界内に含まれます。一連の条件の下で、アラームはビューモデルによってトリガされます。アラームは、境界線の背景に点滅する色のアニメーションとしてビューにレンダリングされ、ユーザーの注意を引き付けます。なぜこのMultiDataTriggerはアニメーションで例外をスローしますか?
問題は、アラームがトリガされ、ユーザーが詳細を取得するために実行時にデータ型を変更した場合、マルチデータトリガアラームを使用するとWPFエンジンがアニメーションの例外をスローします。エンジンはDatatriggerを使用しているときに動作し、MultiDataTriggerで他のすべてが同じであればクラッシュします。
例外がある: '(0)(1)' アニメーション化することはできません不変オブジェクトに
問題を実証するサンプルアプリケーション:ビューをホスティングして切り替えるための
1メインウィンドウ。
大小2表示。
1 viewmodel。マルチ単一datatriggersため
1つのリソース辞書
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>
あなたがコードを実行した場合と、アラームとフラッシュをクリックしてくださいコントロールが黒い背景の銀色のボーダーから点滅するオレンジ色に変わります。小さなビューから大きなビューにスライダを移動すると、マルチデータトリガを使用するとwpfから実行時間が得られます。 Dictionar1.xamlのdatatriggerのコメントを外してmultidatatriggerにコメントする場合は、上記を繰り返して、アプリケーションは正常に実行されます。
DataTemplateの変更とデータトリガーでこのマルチデータトリガーギャグが正常に機能するのはなぜですか?単一のデータトリガーとの唯一の違いは、余分なブール値の1つです。どのように修正することができますか?
(はい、これらのブール値を集計するためにviewmodelにプロパティを作成することで回避できますが、これを実行する必要はなく、問題の横にあります。これはwpfのバグのようですか?)
例外とは何ですか? – Mishka
不変オブジェクトで '(0)。(1)'をアニメートできません。 –