根据属性更改Expander模板

时间:2010-11-09 21:41:23

标签: wpf wpf-controls binding

以下是我自定义Expander模板的一部分:

<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. 有没有办法可以为不同的扩展器更改模板中定义的动画的持续时间,还是需要创建单独的模板?

  3. 感谢。

2 个答案:

答案 0 :(得分:0)

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

<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对象才能使它们成为线程安全的。如果故事板或其子时间轴包含动态资源引用或数据绑定表达式,则无法冻结它。

我不太确定为什么“Style中的所有内容都必须是线程安全的”。我可以看到在多个线程中使用的样式(例如控件的默认样式)是必要的。也许他们只是强制要求所有样式的一致性。但无论如何,看起来样式中的动画不会包含任何类型的动态值,这表明你无法做出你要求的第二件事。

答案 1 :(得分:0)

第二个问题,

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

在您能够以这种方式使用它之后

<local:MyCustomExpander Time="2"/>

您的默认模板将获得此值。 (我没有亲自尝试过,所以我无法保证其有效性)