Changing Expander template based on properties
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:
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 beha开发者_JAVA技巧ves (have it change the Height if the ExpandDirection is up or down and the Width if the ExpandDirection is left or right)?
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.
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.
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 )
精彩评论