【问题标题】:WPF -- it's gotta be easier than I'm making itWPF——它比我做的要容易
【发布时间】:2009-08-06 12:21:39
【问题描述】:

我花了最糟糕的时间来解决这个问题:假设我有两个 Button 和三个 TextBlock。我希望任何一个按钮都能在所有 TextBlocks 上触发一个简单的故事板。目前我正在尝试定义一个包含情节提要的通用文本块样式,然后触发器来自任何按钮单击。这是我最近的一次,但应用程序在启动时崩溃......我在这里没有错:

<Window.Resources>

<Style TargetType="TextBlock" >
    <Setter Property="Foreground" Value="Blue" />
    <Style.Resources>
        <Storyboard x:Key="TextBlockOpacity" Storyboard.TargetProperty="Opacity">
            <DoubleAnimation From="0" To="1" />
        </Storyboard>
    </Style.Resources>      
</Style>

<Window.Triggers>
    <EventTrigger RoutedEvent="ButtonBase.Click" SourceName="button">
        <BeginStoryboard Storyboard="{StaticResource TextBlockOpacity}"/>
    </EventTrigger>
</Window.Triggers>


<Grid x:Name="LayoutRoot">
    <Button x:Name="button" HorizontalAlignment="Left" Margin="51,54,0,0" VerticalAlignment="Top" Width="96" Height="45" Content="Button"/>

    <TextBlock x:Name="textBlock1" Margin="228,54,172,0" VerticalAlignment="Top" Height="45" FontSize="26.667" Text="TextBlock" TextWrapping="Wrap" />
    <TextBlock x:Name="textBlock2" Margin="228,103,172,0" VerticalAlignment="Top" Height="45" FontSize="26.667" Text="Hello" TextWrapping="Wrap"/>
</Grid>

【问题讨论】:

  • 你能不能试着给故事板一个名字,然后看看你是否可以在代码隐藏中正确地 Begin() 它?
  • 您是否在这里问同样的问题:stackoverflow.com/questions/1238817/wpf-animation-question 或者您是否正在寻找 2 按钮单击触发器?
  • 我认为有代表的人需要将此问题与我在上述评论中引用的问题结合起来。

标签: wpf button triggers textblock


【解决方案1】:

如果您“专用”按钮来更改不透明度,则可以利用其DataContext 并为其设置动画。然后只需将元素的Opacity 绑定到DataContext

(我还稍微重构了您的 xaml)

<Window x:Class="SomeNamespace.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:System="clr-namespace:System;assembly=mscorlib"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>        
        <Storyboard x:Key="TextBlockOpacity" Storyboard.TargetName="button1" Storyboard.TargetProperty="DataContext" >
            <DoubleAnimation From="0.1" To="1"/>
        </Storyboard>        
        <Style TargetType="TextBlock" >
            <Setter Property="Foreground" Value="Blue" />
            <Setter Property="Background" Value="LightGray" />
            <Setter Property="FontSize" Value="26.667" />
            <Setter Property="TextWrapping" Value="Wrap" />
            <Setter Property="Height" Value="45" />            
            <Setter Property="Opacity" Value="{Binding ElementName=button1, Path=DataContext}"/>
        </Style>
    </Window.Resources>

    <Window.Triggers>
        <EventTrigger RoutedEvent="ButtonBase.Click">
            <BeginStoryboard Storyboard="{StaticResource TextBlockOpacity}" >
            </BeginStoryboard>
        </EventTrigger>

        <EventTrigger RoutedEvent="ListBox.SelectionChanged">
            <BeginStoryboard Storyboard="{StaticResource TextBlockOpacity}" >
            </BeginStoryboard>
        </EventTrigger>
    </Window.Triggers>

    <Grid x:Name="LayoutRoot">
        <Button x:Name="button1" HorizontalAlignment="Left" Margin="51,54,0,0" VerticalAlignment="Top" Width="96" Height="45" Content="Button">
            <Button.DataContext>
                <System:Double>0</System:Double>
            </Button.DataContext>
        </Button>

        <Button x:Name="button2" HorizontalAlignment="Right" Margin="0,54,29,0" VerticalAlignment="Top" Width="96" Height="45" Content="Button"/>

        <ListBox x:Name="listBox1" Height="50" VerticalAlignment="Top">
            <ListBox.Items>
                <System:String>Text1</System:String>
                <System:String>Text2</System:String>
            </ListBox.Items>
        </ListBox>

        <TextBlock x:Name="textBlock1" Margin="51,114,61,0" Text="TextBlock" Height="45" VerticalAlignment="Top" Width="166" />
        <TextBlock x:Name="textBlock2" Margin="51,0,74,42" Text="Hello" Height="45" Width="153" VerticalAlignment="Bottom" />
    </Grid>
</Window>

还要注意一件事——如果你想最小化你的代码,这是使用的方法,并且让这一切都发生在 xaml 中。您的方法将使整个窗口的Opacity 相结合。这就是为什么在上面的代码中,TextBlocks 绑定到按钮的DataContext,它本身是动画的。

不绑定到一个公共值(DataContext)当然是可行的,但是你需要重复X动画(因为你需要设置X TargetNames)。上面的这种方法更容易扩展和维护。

编辑

为多样性添加了另一个按钮和一个列表框:)

【讨论】:

    【解决方案2】:

    基于kek444的Xaml-only解决方案,我提出了一个稍微改进的版本,它不依赖于按钮的DataContext,可以有多个触发器。

    <Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Class="WpfApplication1.MainWindow"
        x:Name="Window"
        Title="MainWindow"
        Width="640" Height="480">
        <Window.Resources>
            <UIElement x:Key="OpacityCounter" Opacity="0"/>
            <Style TargetType="TextBlock">
                <Setter Property="Opacity" Value="{Binding Source={StaticResource OpacityCounter}, Path=Opacity}" />
            </Style>
            <Storyboard x:Key="OnClick1">
                <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.Target="{StaticResource OpacityCounter}" Storyboard.TargetProperty="(UIElement.Opacity)">
                    <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
                    <SplineDoubleKeyFrame KeyTime="00:00:00.5000000" Value="1"/>
                </DoubleAnimationUsingKeyFrames>
            </Storyboard>
        </Window.Resources>
        <Window.Triggers>
            <EventTrigger RoutedEvent="ButtonBase.Click" SourceName="button1">
                <BeginStoryboard Storyboard="{StaticResource OnClick1}"/>
            </EventTrigger>
            <EventTrigger RoutedEvent="ButtonBase.Click" SourceName="button2">
                <BeginStoryboard Storyboard="{StaticResource OnClick1}"/>
            </EventTrigger>
        </Window.Triggers>
    
        <Grid x:Name="LayoutRoot">
            <StackPanel>
                <StackPanel Orientation="Horizontal">
                    <Button x:Name="button1" Width="131" Height="37" Content="Button 1" Margin="0,0,0,22"/>
                    <Button x:Name="button2" Width="131" Height="37" Content="Button 2" Margin="0,0,0,22"/>
                </StackPanel>
                <TextBlock x:Name="textBlock" Height="27" Text="TextBlock 1" TextWrapping="Wrap" />
                <TextBlock x:Name="textBlock1" Height="27" Text="TextBlock 2" TextWrapping="Wrap" />
                <TextBlock x:Name="textBlock2" Height="27" Text="TextBlock 3" TextWrapping="Wrap" />
                <TextBlock x:Name="textBlock3" Height="27" Text="TextBlock 4" TextWrapping="Wrap" />
            </StackPanel>
        </Grid>
    </Window>
    

    要将 ListBox 用作触发机制(假设您在某个地方有一个名为“listbox1”的 ListBox,请将以下内容添加到 Window.Triggers:

    <EventTrigger RoutedEvent="Selector.SelectionChanged" SourceName="listbox1">
        <BeginStoryboard Storyboard="{StaticResource OnClick1}"/>
    </EventTrigger>
    

    或者要触发特定的 ListBoxItem,您需要(其中 item1 是一个命名的 ListBoxItem):

    <EventTrigger RoutedEvent="ListBoxItem.Selected" SourceName="item1">
        <BeginStoryboard Storyboard="{StaticResource OnClick1}"/>
    </EventTrigger>
    

    【讨论】:

    • 那太好了!我想避免将 UIElements 创建为资源,但人们应该选择更适合他们的东西。但是,基于它不使用 DataContext 并且支持多个触发器这一事实来调用这种方法是改进的,这有点不公平。在 DataContext 上使用资源 UIElement 只是个人喜好问题;并且两种解决方案都支持多个触发器。否则,干得好。 ;)
    • 好的...现在让它稍微复杂一些...我并不是真的试图触发按钮,而是触发来自 StackPanel 内的 ListBox 的 ListBoxItem 更改,在边框内,在主窗口的网格内。我已经尝试了几个小时,但无法获得正确的 RoutedEvent...所有 ListBoxItem 事件都会给出关于类被密封或其他东西的错误...
    • 我只称它为改进,因为它不需要为每个触发机制(即按钮)提供单独的 DataContext。我不是故意冒犯的。
    • 没关系,无意冒犯,只是想指出来。您应该注意,不需要多个 DataContext。为了完整起见,我稍微扩展了示例。
    • @unknown(google):出现错误是因为程序集不是为新资源访问而构建的。它应该在构建之后工作。
    【解决方案3】:

    在您的示例中,您将 Style 中的 Storyboard 定义为资源,但随后您尝试将其作为 Window 资源进行访问。尝试将 Storyboard 声明移至 Window.Resources,然后在 Style 中引用 Storyboard。

    我不知道它是否会做你想做的事,但我会从那里开始。

    【讨论】:

    • 好吧,我一直在绕着这个问题奔波,但归结为 NameScope。我有一个 ListBox,我想在 TextBlocks 上触发动画,但它们不在同一个 NameScope 中,所以如果我将 StoryBoard 放在 Windows.Resources 中,那么 ListBox 触发器可以找到 StoryBoard 但 StoryBoard 找不到文本块的目标名称。如果我将 StoryBoard 放在 Grid.Resource(TextBlock 所在的位置)中,则 ListBox 更改触发器找不到 StoryBoard。我可以使用一些命名约定来跨名称范围吗?啊!谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-22
    • 1970-01-01
    相关资源
    最近更新 更多