1

我正在寻找在ControlTemplate. 在我的应用程序中,我有从以下位置创建的自定义模板按钮(扮演菜单角色)ObservableCollection

主菜单视图模型:

/// <summary>
/// Menu items list
/// </summary>
private ObservableCollection<MenuItem> _items;

....

/// <summary>
/// Menu items list property
/// </summary>
public ObservableCollection<MenuItem> Items
{
    get { return _items; }
    set { _items = value; }
}

主菜单视图:

<UserControl x:Class="OfficeTourismeBrantome.Views.MainMenuView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="800" d:DesignWidth="300">
    <UserControl.Resources>
        <Style x:Key="MenuItemButtonStyle" TargetType="Button">
            <Setter Property="FontSize" Value="60" />
            <Setter Property="FontFamily" Value="Segoe" />
            <Setter Property="FontWeight" Value="UltraLight" />
            <Setter Property="Foreground" Value="#FFEBEDEA" />
            <!--<Setter Property="Height" Value="{Binding MenuLayout.MenuItemSize.Height}" />-->
            <Setter Property="HorizontalContentAlignment" Value="Right" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <ControlTemplate.Triggers>
                            <EventTrigger RoutedEvent="Button.Click">
                                <EventTrigger.Actions>
                                    <BeginStoryboard>
                                        <Storyboard Name="themeSelectionAnimation">
                                            <DoubleAnimation 
                                                Storyboard.TargetName="coloredRectangle"
                                                Storyboard.TargetProperty="Width"
                                                From="30.0" 
                                                To="250.0" 
                                                Duration="0:0:0.3" />
                                        </Storyboard>
                                    </BeginStoryboard>                                    
                                </EventTrigger.Actions>
                            </EventTrigger>
                        </ControlTemplate.Triggers>
                        <Canvas HorizontalAlignment="Stretch" ClipToBounds="False" >
                            <ContentPresenter Canvas.Left="{Binding MenuLayout.MenuItemLeftMargin}" HorizontalAlignment="Center"                                                  
                                            VerticalAlignment="Center" Canvas.ZIndex="1"/>
                            <TextBlock 
                                Text="{Binding SecondaryText}" 
                                Canvas.Top="50"
                                Canvas.Left="10"
                                FontSize="30"
                                FontWeight="ExtraLight"
                                FontStyle="Italic"
                                Canvas.ZIndex="1"
                                />
                            <Rectangle
                                Canvas.Top="30"
                                Canvas.Left="10"
                                Name="coloredRectangle"
                                Width="30"
                                Height="10"
                                Canvas.ZIndex="0"
                                Fill="{Binding Color}"/>
                        </Canvas>                        
                    </ControlTemplate>                    
                </Setter.Value>
            </Setter>             
        </Style>
        <Storyboard x:Key="themeUnselectionAnimation">
            <DoubleAnimation                 
                Storyboard.TargetProperty="Width"
                From="250.0" 
                To="30.0" 
                Duration="0:0:0.15" />
        </Storyboard>
    </UserControl.Resources>
    <ItemsControl Name="menuButtonContainer" ItemsSource="{Binding Items}" Margin="{Binding MenuLayout.MenuMargin}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Vertical" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>        
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Button 
                    Style="{StaticResource ResourceKey=MenuItemButtonStyle}" 
                    Margin="{Binding ElementName=menuButtonContainer, 
                                        Path=DataContext.MenuLayout.MenuItemMargin}"                    
                    Height="{Binding ElementName=menuButtonContainer, 
                                        Path=DataContext.MenuLayout.MenuItemSize.Height}"
                    Content="{Binding Text}"                    
                    Command="{Binding ElementName=menuButtonContainer, 
                                        Path=DataContext.ChangeThemeCommand}"
                    CommandParameter="{Binding Id}"
                    />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</UserControl>

正如您在上面的代码中看到的,我在按钮单击时自动触发了一个动画。当单击集合中的另一个按钮(选择另一个菜单项)时,我想反向播放它。要播放的动画是名为 themeUnselectionAnimation 的动画。

第一个问题:有没有办法只在 XAML 中做到这一点?我不确定是否需要按下另一个按钮才能触发它。

以下是我的想法:

  1. Button(这是我的菜单项)命令操作中,发送一条消息让订阅者知道菜单项正在更改。
  2. MainMenuView在代码隐藏中注册它。
  3. 从那里启动动画。

到目前为止,我的问题是为动画设置目标控件。为此,我Rectangle需要coloredRectangleControlTemplate. 怎么做 ?

下面是我对应于上述步骤的代码:

第 1 步:发送消息(我正在使用 MVVM Light 框架)

/// <summary>
/// Delegates that handles theme change process and tasks
/// </summary>
/// <param name="themeId">the new active theme</param>
private void ChangeTheme(int themeId)
{
    // Set current active theme as inactive, if one is selected.
    // Exception use because of Single implementation that throw an InvalidOperationException if not item is found
    try
    {
        MenuItem currentTheme = Items.Single(x => x.IsActive == true);

        // Check if this is current theme. If it is, we do nothing.
        if(currentTheme.Id == themeId)
            return;

        // If current theme is set and new theme id is not the same, disable the old one
        currentTheme.IsActive = false;
        // Set new theme as active
        Items.Single(x => x.Id == themeId).IsActive = true;

        // Finally, launch unselection animation

        // Send message and register to it in view code behind
        // Create inner message
        ThemeChangeNotification innerMessage = new ThemeChangeNotification();
        innerMessage.NewThemeId = themeId;
        innerMessage.OldThemeId = currentTheme.Id;

        NotificationMessage<ThemeChangeNotification> message =
            new NotificationMessage<ThemeChangeNotification>(innerMessage, "");
        // Send message
        Messenger.Default.Send(message);                
    }
    catch (InvalidOperationException exception)
    {
        // Set first theme selection as active
        Items.Single(x => x.Id == themeId).IsActive = true;
    }                                    
}

第二步:注册留言

Messenger.Default.Register<NotificationMessage<ThemeChangeNotification>>(this, ChangeThemeAnimation);

第 3 步:从 index/id 到达 Button 并启动动画(不工作)

/// <summary>
/// Theme change message delegate
/// </summary>
/// <param name="e">The ThemeChangeNotification message</param>
private void ChangeThemeAnimation(NotificationMessage<ThemeChangeNotification> message)
{
    var buttonTheme = menuButtonContainer.ItemContainerGenerator.ContainerFromIndex(message.Content.OldThemeId) as FrameworkElement;
    var rectangle = buttonTheme.FindName("coloredRectangle") as Rectangle;
    Storyboard sb = this.FindResource("themeUnselectionAnimation") as Storyboard;
    Storyboard.SetTarget(sb, rectangle);
    sb.Begin();
}

非常感谢您的回答!

4

1 回答 1

1

当然,您可以Style根据第一个使用另一个Storyboard来创建另一个...然后您可以将反向应用到您想要启动的Style任何一个(s)上: ButtonStoryboard

<Style x:Key="ReverseMenuItemButtonStyle" TargetType="Button">
    <Setter Property="FontSize" Value="60" />
    <Setter Property="FontFamily" Value="Segoe" />
    <Setter Property="FontWeight" Value="UltraLight" />
    <Setter Property="Foreground" Value="#FFEBEDEA" />
    <Setter Property="HorizontalContentAlignment" Value="Right" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <ControlTemplate.Triggers>
                    <EventTrigger RoutedEvent="Button.Click">
                        <EventTrigger.Actions>
                            <BeginStoryboard>
                                <Storyboard Name="themeUnselectionAnimation">
                                    <DoubleAnimation 
                                        Storyboard.TargetName="coloredRectangle"
                                        Storyboard.TargetProperty="Width"
                                        From="30.0" 
                                        To="250.0" 
                                        Duration="0:0:0.3" />
                                </Storyboard>
                            </BeginStoryboard>                                    
                        </EventTrigger.Actions>
                    </EventTrigger>
                </ControlTemplate.Triggers>
                ...
            </ControlTemplate>                    
        </Setter.Value>
    </Setter>             
</Style>

我必须完全诚实......我并不完全理解你的问题,所以如果没有回答它,似乎你也想知道如何Storyboard从视图模型开始。在这种情况下,您只需要一个在视图模型中bool设置为时将启动动画的属性。true您可以使用DataTrigger.EnterActions

<Style>
    <Style.Triggers>
        <DataTrigger Binding="{Binding SomeBooleanPropertyInViewModel}" Value="True">
            <DataTrigger.EnterActions>
                <BeginStoryboard>
                    <Storyboard ... />
                </BeginStoryboard>
            </DataTrigger.EnterActions>
        </DataTrigger>
    </Style.Triggers>
</Style>

更新>>>

再次......我仍然不知道你在追求什么......我建议在发布另一个问题之前先研究你的提问技巧。但是,我可以解决这么多:

您收到TargetName cannot be used on Style Setter错误,并且您想要定位您的coloredRectangle元素。

此错误的通常修复方法是将您移动Trigger到您尝试定位的元素。所以试试这个:

<Rectangle Canvas.Top="30" Canvas.Left="10" Name="coloredRectangle" ... >
    <Rectangle.Style>
        <Style>
            <Style.Triggers>
                <DataTrigger Binding="{Binding SomeBooleanProperty}" Value="True">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard ... />
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Rectangle.Style>
</Rectangle>
于 2014-03-05T21:50:58.873 回答