使用 VisualStateManager 对 MVVM ViewModel 过渡进行动画处理 -- 动画未运行



我正在开发我的第一个WPF项目,基于MVVM Light工具包。 主视图在数据绑定ContentControl中保存任意视图模型,如下所示:

<ContentControl x:Name="ViewModelContent" Content="{Binding CurrentViewModel}" ... />

我想做的是,每当这个视图模型发生变化时,淡出旧的视图模型(即ContentControl),然后淡入新的视图模型。 这在 WPF 世界中并不是一个新想法,我花了相当多的时间研究如何实现它(无论是在这里还是在其他网站上)。 我试图保持相对简单,我收集的是我可以使用VisualStateManager在视图DataTemplate上定义两种状态:

  • 内容更改:淡出状态
  • 内容已更改:淡入状态

然后,使用 GoToStateAction ,我可以根据需要将动画动画化到适当的状态。 就我而言,"根据需要"是通过在我的 ViewModel 上定义的CurrentViewModelChanging属性完成的(请记住,我使用的是 MVVM Light):

private bool _vmChanging;
public bool CurrentViewModelChanging
{
    get
    {
        return _vmChanging;
    }
    private set
    {
        Set(() => CurrentViewModelChanging, ref _vmChanging, value);
    }
}

然后,我可以利用DataTrigger绑定到此属性并相应地更改状态。 在 XAML 中,DataTemplate它如下所示:

<i:Interaction.Triggers>
    <ei:DataTrigger Binding="{Binding CurrentViewModelChanging, Mode=OneWay}" Value="True">
        <ei:GoToStateAction StateName="ContentChanging"/>
    </ei:DataTrigger>
    <ei:DataTrigger Binding="{Binding CurrentViewModelChanging, Mode=OneWay}" Value="False">
        <ei:GoToStateAction StateName="ContentChanged"/>
    </ei:DataTrigger>
</i:Interaction.Triggers>

目前为止,一切都好。 我在窗体上放置了一个按钮,除了切换CurrentViewModelChanging(从而更改状态)之外没有其他用途,它完全符合我的预期:单击它一次会淡出视图,再次单击它会淡入视图。 当我在实际更改视图模型时尝试完成淡出/淡入时,会出现此问题。 这是我尝试的代码片段:

public Standards.StandardsViewModel CurrentViewModel
{
    ....
    private set
    {
        ....
        CurrentViewModelChanging = true;
        Set(() => CurrentViewModel, ref _viewModel, value);
        CurrentViewModelChanging = false;
        ....
    };
}

当它运行时发生的情况基本上什么都没有:ViewModel 在没有任何动画的情况下立即切换。 我的印象是,更改CurrentViewModelChanging会导致动画运行并停止执行任何剩余的代码,直到动画完成。 情况似乎并非如此,所以有人可以告诉我发生了什么(以及如何解决它)吗? 我最好的猜测是动画在与执行逻辑不同的线程中运行,并且所述逻辑执行得如此之快,以至于动画没有时间实际执行任何操作。 但是,如果我在CurrentViewModelChanging切换中放置一个Thread.Sleep()调用,那么我仍然没有得到动画:无论我告诉它多长时间,程序都会挂起,然后立即更改ViewModel。

此外,如果它不明显,这一切都是基于DataTemplate,因此需要我采用UserControls的解决方案并不理想。 但是,如果这就是它所需要的,那么我肯定会这样做。 这是我DataTemplate更完整的 XAML,如果有帮助的话。 请注意,为了简洁起见,我省略了动画的细节:

<DataTemplate DataType="{x:Type localVMS:StandardsModuleViewModel}">
    <DockPanel x:Name="ModLayout" LastChildFill="True" Margin="0" Grid.Column="1">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="ContentPresentationStates">
                <VisualStateGroup.Transitions>
                    <VisualTransition GeneratedDuration="0:0:0.1" To="ContentChanging"/>
                    <VisualTransition GeneratedDuration="0:0:0.1" To="ContentChanged"/>
                </VisualStateGroup.Transitions>
                <VisualState x:Name="ContentChanging" ... />
                <VisualState x:Name="ContentChanged" .... />
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <Grid x:Name="MainMenuGrid" VerticalAlignment="Top" Background="Black" DockPanel.Dock="Top">
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <ItemsControl x:Name="MainMenu" HorizontalAlignment="Left" VerticalAlignment="Bottom" ItemsSource="{Binding MainMenu}" ItemTemplate="{DynamicResource TopMenuItem}" ItemsPanel="{DynamicResource HorizontalMenuTemplate}" FontFamily="Calibri" FontSize="16" MinHeight="20" Background="Transparent" VerticalContentAlignment="Center" HorizontalContentAlignment="Center"/>
        </Grid>
        <ItemsControl x:Name="SubMenu" ItemsSource="{Binding SubMenu}" ItemsPanel="{DynamicResource HorizontalMenuTemplate}" ItemTemplate="{StaticResource SubMenuItem}" DockPanel.Dock="Top" Height="25" VerticalContentAlignment="Center" Background="White" FontFamily="Calibri" FontSize="13.333"/>
        <Grid x:Name="ViewModelLayout" DockPanel.Dock="Bottom">
            <i:Interaction.Triggers>
                <ei:DataTrigger Binding="{Binding CurrentViewModelChanging, Mode=OneWay}" Value="True">
                    <ei:GoToStateAction StateName="ContentChanging"/>
                </ei:DataTrigger>
                <ei:DataTrigger Binding="{Binding CurrentViewModelChanging, Mode=OneWay}" Value="False">
                    <ei:GoToStateAction StateName="ContentChanged"/>
                </ei:DataTrigger>
            </i:Interaction.Triggers>
            <ContentControl x:Name="ViewModelContent" Content="{Binding CurrentViewModel}" ContentTemplateSelector="{StaticResource GenericTemplateSelector}" HorizontalAlignment="Center" VerticalAlignment="Top" Padding="10" HorizontalContentAlignment="Center" Margin="10" RenderTransformOrigin="0.5,0.5" ... />
        </Grid>
    </DockPanel>
</DataTemplate>

问题是您的 ContentControl 一次只能绑定到一个事物。一旦您更改视图模型,与旧模型的绑定就不再存在,因此没有什么可以褪色的。若要解决此问题,必须设置两个重叠的 UserControls 并分别淡入/淡出它们,或者使用帮助程序类为您处理它。

相关内容

  • 没有找到相关文章

最新更新