0

我有一个 ItemsControl,其中的 Items 通过数据绑定添加到一个可观察的集合。每个项目都有一个定义其外观的数据模板。

我试图弄清楚当 VisualStateManager 将 ItemsControl 置于特定状态时,是否可以对 ItemsControl 中的每个项目应用/触发动画。

下面是一张图片 - 当项目控件进入关闭状态时 - 我希望项目控件中的项目缩小并隐藏文本并让数字变得可见。这是否可能使用 VSM 或者我是否需要在创建每个项目时将动画附加到它们,然后在我希望它们更改视觉状态时手动启动它们。

替代文字 http://www.edefine.com/images/misc/drawing1.jpg

4

2 回答 2

3

使用 ObjectAnimationUsingKeyFrames 可以做到这一点,但是这样做非常困难,会导致你扯掉头发,经常让你的视觉工作室崩溃,并且让你用简单的方法做这件事几乎没有什么好处。

简单的方法:

public class TestSwapContentControl : ContentControl 
{
    object StoredOriginalContent;

    public object FullContent
    {
        get { return (object)GetValue(FullContentProperty); }
        set { SetValue(FullContentProperty, value); }
    }

    // Using a DependencyProperty as the backing store for FullContent.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty FullContentProperty =
        DependencyProperty.Register(
            "FullContent"
            , typeof(object)
            , typeof(TestSwapContentControl)
            , null);

    public void SwitchToFullContent()
    {
        if (FullContent != null)
        {
            StoredOriginalContent = Content;
            Content = FullContent;
        }
    }

    public void SwitchToNormalContent()
    {
        if(StoredOriginalContent != null)
        {
            Content = StoredOriginalContent;
        }
    }
}

然后要使用的xaml:

    <local:TestSwapContentControl x:Name="mySwitch">
            <Rectangle Height="50" Width="100" Fill="Black" />
        <local:TestSwapContentControl.FullContent>
                <StackPanel>
                    <TextBlock>1</TextBlock>
                    <TextBlock>2</TextBlock>
                    <TextBlock>3</TextBlock>
                    <TextBlock>4</TextBlock>
                    <Rectangle Height="50" Width="100" Fill="Red" />
                </StackPanel>
            </local:TestSwapContentControl.FullContent>
    </local:TestSwapContentControl>   

在页面中使用以下cs:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        if (myTempBool)
        {
            mySwitch.SwitchToFullContent();
            myTempBool = false;
        }
        else
        {
            mySwitch.SwitchToNormalContent();
            myTempBool = true;
        }
    }

现在,如果您真的需要让其他开发人员完全可以扩展控件,您将需要使用 visualstatemenager,但它确实是个婊子。如果您不知道如何通过 generic.xaml 设置可视状态管理器和状态,这里有一个操作指南:

http://scorbs.com/2008/06/11/parts-states-model-with-visualstatemanager-part-1-of/

这是一个工作示例,但它并不完美,因为我似乎无法直接设置 ContentPresenter 的内容。

using System.Windows;
using System.Windows.Controls;

namespace SilverlightTestApplication
{
    [TemplateVisualState(Name="Normal", GroupName="SizeStates")]
    [TemplateVisualState(Name="Expanded", GroupName="SizeStates")]
    public class TestVSMControl : ContentControl
    {
        public object SmallContent
        {
            get { return (object)GetValue(SmallContentProperty); }
            set { SetValue(SmallContentProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SmallContent.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SmallContentProperty =
            DependencyProperty.Register("SmallContent", typeof(object), typeof(TestVSMControl), null);

        public object LargeContent
        {
            get { return (object)GetValue(LargeContentProperty); }
            set { SetValue(LargeContentProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LargeContent.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LargeContentProperty =
            DependencyProperty.Register("LargeContent", typeof(object), typeof(TestVSMControl), null);

        public bool Pressed
        {
            get { return (bool)GetValue(PressedProperty); }
            set { SetValue(PressedProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Pressed.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PressedProperty =
            DependencyProperty.Register("Pressed", typeof(bool), typeof(TestVSMControl), 
                new PropertyMetadata(new PropertyChangedCallback(PressedPropertyChanged)));

        static void PressedPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var me = sender as TestVSMControl;
            me.ChangeState();
        }

        public TestVSMControl()
        {
            DefaultStyleKey = typeof(TestVSMControl);
        }

        void ChangeState()
        {
            GoToState(true);
        }

        private void GoToState(bool useTransitions)
        {
            if (Pressed)
            {
                VisualStateManager.GoToState(this, "Normal", useTransitions);
            }
            else
            {
                VisualStateManager.GoToState(this, "Expanded", useTransitions);
            }
        }
    }
}

在您的 generic.xaml 中(包括 xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"):

<Style TargetType="local:TestVSMControl">        
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:TestVSMControl">
                <StackPanel>
                    <vsm:VisualStateManager.VisualStateGroups>
                        <vsm:VisualStateGroup x:Name="SizeStates">
                            <vsm:VisualState x:Name="Normal">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Content" Storyboard.TargetName="myContentPresenter" BeginTime="00:00:00" Duration="00:00:00.0010000" >
                                        <ObjectAnimationUsingKeyFrames.KeyFrames>
                                            <DiscreteObjectKeyFrame KeyTime="0:0:0">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <StackPanel>
                                                        <TextBlock>Rararasputin</TextBlock>
                                                        <Button Content="{TemplateBinding SmallContent}" />
                                                    </StackPanel>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames.KeyFrames>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </vsm:VisualState>
                            <vsm:VisualState x:Name="Expanded">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Content" Storyboard.TargetName="myContentPresenter" BeginTime="00:00:00" Duration="00:00:00.0010000" >
                                         <ObjectAnimationUsingKeyFrames.KeyFrames>
                                            <DiscreteObjectKeyFrame KeyTime="0:0:0"  >
                                                <DiscreteObjectKeyFrame.Value>
                                                    <StackPanel>
                                                        <TextBlock>Other one</TextBlock>
                                                        <Button Content="{TemplateBinding LargeContent}" />
                                                    </StackPanel>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames.KeyFrames>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </vsm:VisualState>
                        </vsm:VisualStateGroup>
                    </vsm:VisualStateManager.VisualStateGroups>                        
                    <ContentPresenter x:Name="myContentPresenter" />
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

以及如何在您的页面中使用:

            <local:TestVSMControl x:Name="myVSMControl" Height="200">
                <local:TestVSMControl.SmallContent>
                    <Rectangle Height="50" Width="100" Fill="Red" />
                </local:TestVSMControl.SmallContent>
                <local:TestVSMControl.LargeContent>
                    <Rectangle Height="50" Width="100" Fill="Green" />
                </local:TestVSMControl.LargeContent>        
            </local:TestVSMControl>
            <Button Content="Swap" x:Name="VSMButton" Click="VSMButton_Click"  />

在您的页面中包含以下内容:

    private void VSMButton_Click(object sender, RoutedEventArgs e)
    {
        myVSMControl.Pressed = !myVSMControl.Pressed;
    }
于 2009-04-02T09:36:23.153 回答
1

如果您正在谈论 Silverlight 视觉状态管理器,恐怕这是不可能的。

VisualStates 仅包含 Storyboard 对象,而 Storyboard 对象又包含动画。据我所知,您无法使用它更改模板。

我不确定 WPF VisualStateManager 的功能。

于 2009-03-29T02:05:37.590 回答