WPF数据触发器和故事板
时间:2020-03-05 18:58:03 来源:igfitidea点击:
每当ViewModel / Presentation模型忙时,我都试图触发进度动画。我有一个IsBusy属性,并且ViewModel设置为UserControl的DataContext。 IsBusy属性为true时,触发" progressAnimation"故事板的最佳方法是什么? Blend只允许med在UserControl级别上添加事件触发,而我只能在数据模板中创建属性触发器。
" progressAnimation"被定义为用户控件中的资源。
我尝试将DataTriggers作为样式添加到UserControl上,但是当我尝试启动StoryBoard时,出现以下错误:
'System.Windows.Style' value cannot be assigned to property 'Style' of object'Colorful.Control.SearchPanel'. A Storyboard tree in a Style cannot specify a TargetName. Remove TargetName 'progressWheel'.
ProgressWheel是我要设置动画的对象的名称,因此删除目标名称显然不是我想要的。
我希望使用数据绑定技术在XAML中解决此问题,而不是必须公开事件并通过代码启动/停止动画。
解决方案
回答
我建议使用RoutedEvent而不是IsBusy属性。只需触发OnBusyStarted和OnBusyStopped事件,然后在适当的元素上使用事件触发器即可。
回答
我们可以订阅DataObject类的PropertyChanged事件,并从Usercontrol级别触发RoutedEvent。
为了使RoutedEvent正常工作,我们需要具有从DependancyObject派生的类
回答
更改属性后,可以使用Trigger.EnterAction启动动画。
<Trigger Property="IsBusy" Value="true"> <Trigger.EnterActions> <BeginStoryboard x:Name="BeginBusy" Storyboard="{StaticResource MyStoryboard}" /> </Trigger.EnterActions> <Trigger.ExitActions> <StopStoryboard BeginStoryboardName="BeginBusy" /> </Trigger.ExitActions> </Trigger>
回答
通过在progressWheel本身上声明动画,可以实现所需的操作:
XAML:
<UserControl x:Class="TriggerSpike.UserControl1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="300" Width="300"> <UserControl.Resources> <DoubleAnimation x:Key="SearchAnimation" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:4"/> <DoubleAnimation x:Key="StopSearchAnimation" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:4"/> </UserControl.Resources> <StackPanel> <TextBlock Name="progressWheel" TextAlignment="Center" Opacity="0"> <TextBlock.Style> <Style> <Style.Triggers> <DataTrigger Binding="{Binding IsBusy}" Value="True"> <DataTrigger.EnterActions> <BeginStoryboard> <Storyboard> <StaticResource ResourceKey="SearchAnimation"/> </Storyboard> </BeginStoryboard> </DataTrigger.EnterActions> <DataTrigger.ExitActions> <BeginStoryboard> <Storyboard> <StaticResource ResourceKey="StopSearchAnimation"/> </Storyboard> </BeginStoryboard> </DataTrigger.ExitActions> </DataTrigger> </Style.Triggers> </Style> </TextBlock.Style> Searching </TextBlock> <Label Content="Here your search query"/> <TextBox Text="{Binding SearchClause}"/> <Button Click="Button_Click">Search!</Button> <TextBlock Text="{Binding Result}"/> </StackPanel>
后面的代码:
using System.Windows; using System.Windows.Controls; namespace TriggerSpike { public partial class UserControl1 : UserControl { private MyViewModel myModel; public UserControl1() { myModel=new MyViewModel(); DataContext = myModel; InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { myModel.Search(myModel.SearchClause); } } }
视图模型:
using System.ComponentModel; using System.Threading; using System.Windows; namespace TriggerSpike { class MyViewModel:DependencyObject { public string SearchClause{ get;set;} public bool IsBusy { get { return (bool)GetValue(IsBusyProperty); } set { SetValue(IsBusyProperty, value); } } public static readonly DependencyProperty IsBusyProperty = DependencyProperty.Register("IsBusy", typeof(bool), typeof(MyViewModel), new UIPropertyMetadata(false)); public string Result { get { return (string)GetValue(ResultProperty); } set { SetValue(ResultProperty, value); } } public static readonly DependencyProperty ResultProperty = DependencyProperty.Register("Result", typeof(string), typeof(MyViewModel), new UIPropertyMetadata(string.Empty)); public void Search(string search_clause) { Result = string.Empty; SearchClause = search_clause; var worker = new BackgroundWorker(); worker.DoWork += worker_DoWork; worker.RunWorkerCompleted += worker_RunWorkerCompleted; IsBusy = true; worker.RunWorkerAsync(); } void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { IsBusy=false; Result = "Sorry, no results found for: " + SearchClause; } void worker_DoWork(object sender, DoWorkEventArgs e) { Thread.Sleep(5000); } } }
希望这可以帮助!