使用MVVM模式连接到Storyboard.Complete事件

时间:2013-02-22 15:56:20

标签: wpf data-binding mvvm caliburn.micro

基本上,我得到的是一个简单的警报消息设置。可以看到各个警报,其中一些数据绑定到VM的文本和颜色(成功为绿色,错误为红色等)。

<Border Margin="0 0 0 20" Background="{Binding Path=BackgroundColor}" BorderBrush="#D4D4D4" BorderThickness="1" CornerRadius="8">
    <Border.Effect>
        <DropShadowEffect Color="DarkGray"/>
    </Border.Effect>
<Grid >
        <Button Content="X" HorizontalAlignment="Left" 
            Margin="268,10,0,0" VerticalAlignment="Top" Width="20" RenderTransformOrigin="-0.48,0.727"/>
        <TextBlock x:Name="Message" 
           Foreground="White" FontWeight="SemiBold" FontSize="13px"
           Text="{Binding Path=Message}" 
           HorizontalAlignment="Left" Width="250"
           TextWrapping="Wrap"
           VerticalAlignment="Center" RenderTransformOrigin="-4.395,-0.038" Margin="7,13,0,25"/>
    </Grid>
</Border>

目标是在单击“X”按钮时将其关闭,并使用漂亮的淡入淡出动画。我有一个故事板来处理褪色:

<UserControl.Triggers>
    <EventTrigger RoutedEvent="Button.Click">
        <BeginStoryboard>
            <Storyboard>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)">
                    <EasingDoubleKeyFrame KeyTime="0" Value="1"/>
                    <EasingDoubleKeyFrame KeyTime="0:0:1" Value="0"/>
                </DoubleAnimationUsingKeyFrames>
            </Storyboard>
        </BeginStoryboard>
    </EventTrigger>
</UserControl.Triggers>

现在,我想做的就是让Caliburn.Micro用故事板Completed事件挂钩,用一种方法来模仿实际视图(在另一个视图中有一个可绑定的这些警报集合,以便警报将堆叠,然后根据用户的愿望被解雇。)

我最初尝试过类似的东西,认为它与我的其他任何绑定都一样:

<Storyboard cal:Message.Attach="[Event Completed] = [Action DismissMessage($source, $eventArgs)]">
<!-- rest of the codez... -->

但是出现了以下错误:

Cannot attach type "ActionMessage" to type "Storyboard". Instances of type "ActionMessage" can only be attached to objects of type "FrameworkElement".

这就足够了我猜...但是那么处理像这种绑定之类的东西的最佳方法是什么?我的思绪不可避免地开始徘徊尝试一些hacky解决方案,比如从视图的代码隐藏中调用viewmodel,但它似乎违反了MVVM。

有什么建议吗?

3 个答案:

答案 0 :(得分:2)

正如我所评论的,更简单的方法可能是聚合器。

StoryBoard完成时,您可以通过聚合器(或甚至是对话框的特定聚合器)触发事件,并在VM中处理该事件以关闭对话框

e.g。如果您没有聚合器,则需要提供聚合器的东西(不确定您是否使用DI)

public static DialogEventAggregatorProvider  
{
    public static EventAggregator { get; set; } // Obviously instantiate this, I'll leave the code out for brevity
}

在您的视图中代码隐藏:

public SomeView : UserControl
{
    private void StoryBoard_Completed(object sender, SomeEventArgs e)
    {
        DialogEventAggregatorProvider.EventAggregator.Publish(new CloseDialogMessage()); // Add some args or what have you if it helps identify what dialog to close, but try not to break MVVM ;)
    }
}
虚拟机中的

public SomeViewModel : Screen, IHandle<CloseDialogMessage>
{
    public SomeViewModel() 
    {
        // Don't forget to subscribe or you'll be scratching your head
        DialogEventAggregatorProvider.EventAggregator.Subscribe(this);
    }

    public void Handle(CloseDialogMessage message) 
    { 
        // if(message.HasSomeValue) Here you could check the type of message etc.
           TryClose();
    }
}

这不是那么漂亮,但只要保持实现通用,就可以在不违反MVVM原则的情况下逃脱

答案 1 :(得分:2)

我认为避免查看代码的最佳方法是使用Blend交互库中的StoryboardCompletedTrigger

首先在xaml中包含正确的引用:

xmlns:i="http://schemas.microsoft.com/expression/2010/
xmlns:ie="http://schemas.microsoft.com/expression/2010/interactions"   

然后将您的互动触发器添加到您的视图中,并将其操作设置为CallMethodAction

<i:Interaction.Triggers>
  <ie:StoryboardCompletedTrigger Storyboard="{StaticResource MyStoryboard}">
    <ie:CallMethodAction MethodName="DismissMessage" TargetObject="{Binding}"/>
  </ie:StoryboardCompletedTrigger>
</i:Interaction.Triggers>

答案 2 :(得分:0)

您可以使用Marlon Grech附加命令行为库将该事件绑定到命令。

可以从这里下载库: http://marlongrech.wordpress.com/2008/12/13/attachedcommandbehavior-v2-aka-acb/