根据属性更改扩展器模板

发布于 2024-10-01 06:43:11 字数 2530 浏览 0 评论 0原文

下面是我的自定义扩展器模板的一部分:

<Grid 
    x:Name="ExpandSiteContainer" 
    Visibility="Visible" 
    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
    Margin="{TemplateBinding Padding}" 
    VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
    DockPanel.Dock="Bottom">
        <!--<Grid.Height>
            <MultiBinding Converter="{StaticResource multiplyConverter}">
                <Binding Path="ActualHeight" ElementName="ExpandSite"/>
                <Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
            </MultiBinding>
        </Grid.Height>-->
        <Grid.Width>
            <MultiBinding Converter="{StaticResource multiplyConverter}">
                <Binding Path="ActualWidth" ElementName="ExpandSite"/>
                <Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
            </MultiBinding>
        </Grid.Width>
        <Grid.Tag>
            <sys:Double>0.0</sys:Double>
        </Grid.Tag>
        <ScrollViewer VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden">
            <ContentPresenter x:Name="ExpandSite" Focusable="false" VerticalAlignment="Top"/>
        </ScrollViewer>
</Grid>

我还定义了以下触发器:

<Trigger Property="IsExpanded" Value="true">
    <Trigger.EnterActions>
        <BeginStoryboard>
            <Storyboard>
                <DoubleAnimation Storyboard.TargetName ="ExpandSiteContainer" Storyboard.TargetProperty = "Tag" To="1.0" Duration ="0:0:0.25" />
            </Storyboard>
        </BeginStoryboard>
    </Trigger.EnterActions>
    <Trigger.ExitActions>
        <BeginStoryboard>
            <Storyboard>
                <DoubleAnimation Storyboard.TargetName ="ExpandSiteContainer" Storyboard.TargetProperty ="Tag" To="0" Duration ="0:0:0.25"/>
            </Storyboard>
        </BeginStoryboard>
    </Trigger.ExitActions>
</Trigger>

每当 IsExpanded 属性发生更改时,扩展器将使用上面定义的故事板滑动打开/关闭。

我想做的是以某种方式“传入”将修改其行为的值:

  1. 请注意,模板中的 Grid.Height 部分已被注释掉。它被注释掉了,因为现在我的扩展器向右扩展,我只想修改网格的宽度。我可以做些什么,以便根据扩展器的 ExpandDirection,我可以更改模板的行为方式(如果 ExpandDirection 向上或向下,则更改高度;如果 ExpandDirection 向左或向右,则更改宽度)?

  2. 有没有办法可以更改模板中为不同扩展器定义的动画的持续时间,或者我是否需要创建单独的模板?

谢谢。

Below is a section of my customized Expander template:

<Grid 
    x:Name="ExpandSiteContainer" 
    Visibility="Visible" 
    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
    Margin="{TemplateBinding Padding}" 
    VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
    DockPanel.Dock="Bottom">
        <!--<Grid.Height>
            <MultiBinding Converter="{StaticResource multiplyConverter}">
                <Binding Path="ActualHeight" ElementName="ExpandSite"/>
                <Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
            </MultiBinding>
        </Grid.Height>-->
        <Grid.Width>
            <MultiBinding Converter="{StaticResource multiplyConverter}">
                <Binding Path="ActualWidth" ElementName="ExpandSite"/>
                <Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
            </MultiBinding>
        </Grid.Width>
        <Grid.Tag>
            <sys:Double>0.0</sys:Double>
        </Grid.Tag>
        <ScrollViewer VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden">
            <ContentPresenter x:Name="ExpandSite" Focusable="false" VerticalAlignment="Top"/>
        </ScrollViewer>
</Grid>

I also have the following trigger defined:

<Trigger Property="IsExpanded" Value="true">
    <Trigger.EnterActions>
        <BeginStoryboard>
            <Storyboard>
                <DoubleAnimation Storyboard.TargetName ="ExpandSiteContainer" Storyboard.TargetProperty = "Tag" To="1.0" Duration ="0:0:0.25" />
            </Storyboard>
        </BeginStoryboard>
    </Trigger.EnterActions>
    <Trigger.ExitActions>
        <BeginStoryboard>
            <Storyboard>
                <DoubleAnimation Storyboard.TargetName ="ExpandSiteContainer" Storyboard.TargetProperty ="Tag" To="0" Duration ="0:0:0.25"/>
            </Storyboard>
        </BeginStoryboard>
    </Trigger.ExitActions>
</Trigger>

What happens is that the expander will slide open/closed using the above defined storyboards whenever the IsExpanded property changes.

What I would like to do is somehow "pass in" values that will modify its behavior:

  1. Notice that the Grid.Height section in the template is commented out. It's commented out because right now my expander expands to the right and I want to modify only the width of the Grid. Is there anything I can do so that depending on the ExpandDirection of the expander, I can change how the template behaves (have it change the Height if the ExpandDirection is up or down and the Width if the ExpandDirection is left or right)?

  2. Is there a way I can change the duration times of the animation defined in the template for different expanders or do I need to create separate templates?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

幸福不弃 2024-10-08 06:43:11

对于问题 1,您可以使用触发器根据 ExpandDirection 选择扩展行为。从 Grid 中删除 Grid.WidthGrid.Height,然后将其添加到模板的触发器中:

<Trigger Property="ExpandDirection" Value="Down">
    <Setter TargetName="ExpandSiteContainer" Property="Height">
        <Setter.Value>
            <MultiBinding Converter="{StaticResource multiplyConverter}">
                <Binding Path="ActualHeight" ElementName="ExpandSite"/>
                <Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
            </MultiBinding>
        </Setter.Value>
    </Setter>
</Trigger>
<Trigger Property="ExpandDirection" Value="Right">
    <Setter TargetName="ExpandSiteContainer" Property="Width">
        <Setter.Value>
            <MultiBinding Converter="{StaticResource multiplyConverter}">
                <Binding Path="ActualWidth" ElementName="ExpandSite"/>
                <Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
            </MultiBinding>
        </Setter.Value>
    </Setter>
</Trigger>

对于问题 2,我认为答案可能是:不。问题是,WPF 最终将尝试冻结动画,因为它是 Style 的一部分,这使得很难执行任何修改持续时间的操作。 (例如,如果您尝试对动画的 Duration 进行数据绑定,则会在初始化期间收到错误,因为 WPF 尝试冻结 Storyboard,这会立即引发异常,表明它不能冻结。)

据我了解,样式冻结其资源的原因是因为这使得资源可以在样式的多个实例之间更有效地共享。正如http://msdn.microsoft.com/library/ms742868中所述

您不能使用动态资源引用或数据绑定表达式来设置 Storyboard 或动画属性值。这是因为 Style 内的所有内容都必须是线程安全的,并且计时系统必须冻结 Storyboard 对象以使其成为线程安全的。如果 Storyboard 或其子时间线包含动态资源引用或数据绑定表达式,则无法冻结 Storyboard。

我不太清楚为什么“样式内的所有内容都必须是线程安全的”。我可以看到这对于跨多个线程使用的样式(例如控件的默认样式)是必要的。也许他们只是对所有样式强制要求一致性。但无论如何,样式内的动画似乎无法包含任何类型的动态值,这表明您将无法执行您要求的第二件事。

On question 1, you could use triggers to select the expansion behaviour based on the ExpandDirection. remove both the Grid.Width and Grid.Height from the Grid, and then add this inside your template's triggers:

<Trigger Property="ExpandDirection" Value="Down">
    <Setter TargetName="ExpandSiteContainer" Property="Height">
        <Setter.Value>
            <MultiBinding Converter="{StaticResource multiplyConverter}">
                <Binding Path="ActualHeight" ElementName="ExpandSite"/>
                <Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
            </MultiBinding>
        </Setter.Value>
    </Setter>
</Trigger>
<Trigger Property="ExpandDirection" Value="Right">
    <Setter TargetName="ExpandSiteContainer" Property="Width">
        <Setter.Value>
            <MultiBinding Converter="{StaticResource multiplyConverter}">
                <Binding Path="ActualWidth" ElementName="ExpandSite"/>
                <Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
            </MultiBinding>
        </Setter.Value>
    </Setter>
</Trigger>

For question 2, I think the answer may be: no. The problem is, WPF will end up trying to freeze the animation because it's part of a Style, and that makes it hard to do anything that modifies the duration. (E.g., if you attempt to databind the animation's Duration, you get an error during initialization because WPF tries to freeze the Storyboard, which promptly throws an exception to say it cannot be frozen.)

As I understand it, the reason styles freeze their resources is because this enables the resources to be shared more efficiently across multiple instances of the style. As it says in http://msdn.microsoft.com/library/ms742868

You can't use dynamic resource references or data binding expressions to set Storyboard or animation property values. That's because everything inside a Style must be thread-safe, and the timing system must Freeze Storyboard objects to make them thread-safe. A Storyboard cannot be frozen if it or its child timelines contain dynamic resource references or data binding expressions.

I'm not quite sure why "everything inside a Style must be thread-safe". I can see that'd be necessary on styles that are used across multiple threads (e.g. default styles for controls). Perhaps they just enforce the requirement on all styles for consistency. But in any case, it looks like animations inside styles don't get to contain dynamic values of any kind, which suggests you won't be able to do the 2nd thing you're asking for.

拥抱没勇气 2024-10-08 06:43:11

对于第二个问题,

为什么不向自定义扩展器添加依赖属性(例如“时间”),然后在其上绑定 doubleAnimation 的 Duration 属性?

之后您就可以通过这种方式使用它

<local:MyCustomExpander Time="2"/>

并且您的默认模板将获得该值。
(我没有亲自尝试过,所以不能保证效果)

for your second question,

why not adding a dependency property ("time" for example) to your custom expander, and then bind the Duration property of the doubleAnimation on it ?

After you would be able to use it by this way

<local:MyCustomExpander Time="2"/>

And your default template will get this value.
(I have not tried by myself, so I can't guarantee the effectiveness )

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文