挂入Storyboard.Complete事件与MVVM模式 [英] Hooking into a Storyboard.Complete event with MVVM pattern

查看:288
本文介绍了挂入Storyboard.Complete事件与MVVM模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基本上,我所得到的是一个简单的警报消息设置。有一个视图可以看到一些数据绑定到虚拟机的文本和颜色(绿色为成功,红色为错误等)。

 < Border Margin =0 0 0 20Background ={Binding Path = BackgroundColor}BorderBrush =#D4D4D4BorderThickness =1CornerRadius =8> 
< Border.Effect>
< DropShadowEffect Color =DarkGray/>
< /Border.Effect>
< Grid>
< Button Content =XHorizo​​ntalAlignment =Left
Margin =268,10,0,0VerticalAlignment =TopWidth =20RenderTransformOrigin = - 0.48,0.727 />
< TextBlock x:Name =Message
Foreground =WhiteFontWeight =SemiBoldFontSize =13px
Text ={Binding Path = Message}
Horizo​​ntalAlignment =LeftWidth =250
TextWrapping =Wrap
VerticalAlignment =CenterRenderTransformOrigin = - 4.395,-0.038Margin =7,13,0,25/ >
< / Grid>
< / Border>

目标是让用户点击X按钮,动画。我有一个故事板来处理褪色:

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

现在,我想做的是将Caliburn.Micro钩入故事板的已完成事件,使用一种方法来调整实际视图(在另一个视图中存在这些警报的可绑定集合,以便警报将进行堆叠,然后根据用户的需要被关闭)。



我首先尝试过这样的东西,认为它会像我的其他绑定一样工作:

 < Storyboard cal:Message.Attach =[Event Completed] = [Action DismissMessage($ source,$ eventArgs)]> 
<! - 其余的codez ... - >

但是出现以下错误:

 无法附加类型ActionMessage键入故事板。类型ActionMessage的实例只能附加到FrameworkElement类型的对象。 

这样做很有意义,我猜...但是那么最好的办法是处理什么喜欢这个绑定?我的想法不可避免地开始漫游,尝试一些恶意的解决方案,例如从视图的代码隐藏中调用viewmodel,但它似乎违反了MVVM。



任何建议? p>

解决方案

如我所说,更简单的出路可能是聚合器。



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



eg您将需要一些提供聚合器的东西,如果您没有(不确定是否使用DI)。

  public static DialogEventAggregatorProvider 
{
public static EventAggregator {get;组; } //显然实例化了,为了简洁起见,我将离开代码
}

在你的意见中codebehind:

  public SomeView:UserControl 
{
private void StoryBoard_Completed(object sender,SomeEventArgs e)
{
DialogEventAggregatorProvider.EventAggregator.Publish(new CloseDialogMessage()); //添加一些args或者你有什么帮助确定要关闭的对话框,但是尽量不要打破MVVM;)
}
}



  public SomeViewModel:屏幕,IHandle< CloseDialogMessage> ; 
{
public SomeViewModel()
{
//不要忘记订阅或者你会抓到你的头
DialogEventAggregatorProvider.EventAggregator.Subscribe(this) ;
}

public void Handle(CloseDialogMessage message)
{
// if(message.HasSomeValue)在这里你可以检查消息的类型
TryClose();
}
}

这不是很漂亮,但只要你保持您可以在不违反MVVM原则的情况下获得实现通用。


Basically, what I've got is a simple alert message setup. There is a view for the individual alerts with some data-binding to the VM for their text and color (green for success, red for error, etc.).

<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>

The goal is to have them be dismissed when you click the 'X' button, with a nice fade animation. I've got a storyboard in to handle the fading:

<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>

Now, what I wanted to do is then have Caliburn.Micro hook into the storyboard's Completed event with a method to dimiss the actual view (there is a bindable collection of these alerts in another view so that the alerts will stack and then be dismissed at the user's desire).

I tried something like this at first, thinking that it would work the same as any of my other bindings:

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

But got the following error:

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

And this makes well enough sense I guess...but then what is the best way to handle something like this binding? My mind inevitably starts to wander to attempting some hacky solution like calling the viewmodel from the view's code-behind, but it seems like that violates MVVM.

Any suggestions?

解决方案

As I've commented, an easier way out might be the aggregator.

When the StoryBoard completes, you can just fire an event via the aggregator (or a specific aggregator for dialogs even) and handle that in the VM to close the dialog

e.g. you will need something that provides the aggregator if you don't have one (not sure if you are using DI or not)

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

in your views codebehind:

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 ;)
    }
}

in the VM

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();
    }
}

It's not that pretty, but as long as you keep the implementation generic you can get away without violating MVVM principles

这篇关于挂入Storyboard.Complete事件与MVVM模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆