考虑以下代码:
<UserControl x:Class="MyApp.MyControl"
...
xmlns:local="clr-namespace:MyApp"
DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}">
<UserControl.Template>
<ControlTemplate>
<ControlTemplate.Resources>
<Storyboard x:Key="MyStory">
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" Storyboard.TargetName="brdBase">
<SplineColorKeyFrame KeyTime="0:0:1" Value="Red"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
<Border x:Name="brdBase" BorderThickness="1" BorderBrush="Cyan" Background="Black">
...
</Border>
<ControlTemplate.Triggers>
<Trigger SourceName="brdBase" Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource MyStory}"/>
</Trigger.EnterActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</UserControl.Template>
</UserControl>
Run Code Online (Sandbox Code Playgroud)
上面的代码没有问题.现在,我想将关键帧值绑定到此用户控件MyStory的DP(命名SpecialColor),如下所示:
<Storyboard x:Key="MyStory">
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" Storyboard.TargetName="brdBase">
<SplineColorKeyFrame KeyTime="0:0:1" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:MyControl}}, Path=SpecialColor}"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
Run Code Online (Sandbox Code Playgroud)
这会出错:
无法冻结此Storyboard时间轴树以跨线程使用.
使用后面的代码可以做到这一点.但是我怎么才能在XAML中做到这一点?
代码隐藏辅助解决方案:
► 步骤1:将MyStory故事板放入brdBase资源中.
<UserControl.Template>
<ControlTemplate>
<Border x:Name="brdBase" BorderThickness="1" …Run Code Online (Sandbox Code Playgroud) 我有一个ValueConverter用于绑定StoryBoard动画中的'To'Value,类似于答案 - WPF动画:绑定到storyboard动画的"To"属性.
问题是我MultiBinding ValueConverter在几个地方重复下面的代码.
<MultiBinding Converter="{StaticResource multiplyConverter}">
<Binding Path="ActualHeight" ElementName="ExpanderContent"/>
<Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
</MultiBinding>
Run Code Online (Sandbox Code Playgroud)
我想通过将结果存储ValueConverter到资源变量来删除此重复代码,以便我可以将此本地变量直接绑定到故事板.
<system:Double x:Key="CalculatedWidth">
<MultiBinding Converter="{StaticResource multiplyConverter}">
<Binding Path="ActualHeight" ElementName="ExpanderContent"/>
<Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</system:Double >
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
"Double"类型不支持直接内容.
无法将内容添加到"Double"类型的对象.
我觉得这是一个常见问题,但无法找到解决方案来消除这种冗余.
更新
谢谢Rohit,你的答案解决了这个问题.但我还有一个相关的问题,所以更新问题.这个变量CalculatedWidth在正常情况下工作正常,但是当它在RenderTransform中使用时,它不会获取值.即如果我使用正常的方式使用转换器它可以工作,但它不会获取变量.
<StackPanel.RenderTransform>
<TranslateTransform x:Name="SliderTransform">
<TranslateTransform.X>
<Binding Converter="{StaticResource PanelConverter}" ElementName="SliderPanel" Path="ActualWidth" /> // Works
<Binding Path="Width" Source="{StaticResource CalculatedWidth}"/> // Doesn't Work
</TranslateTransform.X>
</TranslateTransform>
</StackPanel.RenderTransform>
Run Code Online (Sandbox Code Playgroud)
我将变量保留为本地资源的一部分.这是否意味着在调用Render变换时不会创建变量?
为什么我不能将其ActualWidth称为值,我可以在代码中使用它.
XAML:
<StackPanel>
<Button x:Name="cmdVibrate" HorizontalAlignment="Center">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<BeginStoryboard>
<Storyboard >
<DoubleAnimation From="{Binding RelativeSource={RelativeSource Mode=Self},Path=ActualWidth}" By="200" AutoReverse="True" Duration="0:0:1" Storyboard.TargetProperty="Width"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
Mouse over me to shake
</Button>
</StackPanel>
</Window>
Run Code Online (Sandbox Code Playgroud) 我有一个基于 ToggleButton 的自定义控件。在它的构造函数中,我创建了一些类型的元素,FrameworkElementFactory并为其中一个元素分配了一个 EventHandler ,如下所示:
button.AddHandler(Ellipse.MouseDownEvent, new MouseButtonEventHandler(Toggle));
这是我的事件处理程序:
private void Toggle(object sender, EventArgs e)
{
var active = GetTemplateChild("Active");
var button = GetTemplateChild("ToggleButton");
Storyboard sb = new Storyboard();
var ta = new ThicknessAnimation();
Storyboard.SetTargetProperty(ta, new PropertyPath("Margin"));
Storyboard.SetTarget(ta, button);
ta.Duration = TimeSpan.FromSeconds(0.2);
var da = new DoubleAnimation();
Storyboard.SetTargetProperty(da, new PropertyPath("Width"));
Storyboard.SetTarget(da, active);
da.Duration = TimeSpan.FromSeconds(0.2);
if ((bool)IsChecked)
{
ta.To = new Thickness(0);
da.To = (double)button.GetValue(Ellipse.WidthProperty);
IsChecked = !IsChecked;
}
else
{
ta.To = new Thickness(this.Width - (double)button.GetValue(Ellipse.WidthProperty), 0, …Run Code Online (Sandbox Code Playgroud) wpf ×4
c# ×3
xaml ×2
actualwidth ×1
animation ×1
binding ×1
checkbox ×1
expander ×1
storyboard ×1
togglebutton ×1
wpf-controls ×1