【问题标题】:Bind to Control's Property inside VisualStateManager在 VisualStateManager 中绑定到 Control 的属性
【发布时间】:2017-07-18 04:05:45
【问题描述】:

我在 Stackoverflow 上搜索过这个问题,但我认为其他帖子没有涵盖这个问题。

在我的自定义控件中,我使用的是可视状态管理器。在 Visual State Manager 内部有一个动画,它可以为元素的高度设置动画。当我尝试绑定到控件属性时,我在启动时收到以下错误:

附加信息:无法通过引用“RelativeSource FindAncestor, AncestorType=MyNameSpace.MyControl, AncestorLevel='1'”找到绑定源。绑定表达式:路径=实际高度;数据项=空;目标元素是“DoubleAnimation”(HashCode=562002);目标属性是'To'(类型'Nullable`1')

我的控件如下所示:

<Style TargetType="{x:Type local:MyControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:MyControl}">
                <Grid x:Name="RootGrid" >
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CheckStates">
                            <VisualState x:Name="Checked">
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="someElement"
                                                        Storyboard.TargetProperty="Height"
                                                        From="0"
                                                        To="{Binding RelativeSource={RelativeSource AncestorType=local:MyControl},  Path=CustomControlProperty}"
                                                        Duration="0:0:.7" />
...

我尝试了所有的 Bindings 方式,但似乎 Animations 总是将自己作为 Scope。

再次感谢您的帮助。

【问题讨论】:

  • 是的,从那里到父控件不会有可视树关系,所以这会失败。但是RootGrid 将具有与模板化父级相同的ActualHeight,不是吗?我会尝试{Binding ActualHeight, ElementName=RootGrid}。是的,这有点像kludge。如果它甚至有效。
  • 我犯了一个错误。我不想绑定到 Height 属性。如果是这种情况,你是对的。我想绑定到自定义控件中定义的自定义属性。

标签: c# wpf xaml


【解决方案1】:

我能够做到这一点with a BindingProxy。我发现绑定代理不直观。有时他们在第一枪上工作;这个需要一些试验和错误。此外,它们有点像万岁的解决方法。

XAML:

<Grid 
    x:Name="RootGrid"
    >
    <Grid.Resources>
        <!-- 
        When defined in ControlTemplate.Resources, this failed. 
        TemplateBinding failed too. 
        -->
        <local:BindingProxy
            x:Key="CustomControlPropertyProxy"
            Data="{Binding CustomControlProperty, RelativeSource={RelativeSource TemplatedParent}}"
            />
    </Grid.Resources>
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CheckStates">
            <VisualState x:Name="Checked">
                <Storyboard>
                    <DoubleAnimation
                        Storyboard.TargetName="someElement"
                        Storyboard.TargetProperty="Height"
                        From="0"
                        To="{Binding Data, Source={StaticResource CustomControlPropertyProxy}}"
                        Duration="0:0:5"
                        />
                </Storyboard>

C#(被盗,不是第一次,from this answer):

public class BindingProxy : Freezable
{
    #region Overrides of Freezable

    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }

    #endregion

    public object Data
    {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }

    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data", typeof(object),
                                     typeof(BindingProxy));
}

这是 XAML 的另一种变体,以防您最终将动画属性绑定到模板化父级的多个属性:

<Grid 
    x:Name="RootGrid"
    >
    <Grid.Resources>
        <local:BindingProxy
            x:Key="TemplatedParentProxy"
            Data="{Binding ., RelativeSource={RelativeSource TemplatedParent}}"
            />
    </Grid.Resources>
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CheckStates">
            <VisualState x:Name="Checked">
                <Storyboard>
                    <DoubleAnimation
                        Storyboard.TargetName="someElement"
                        Storyboard.TargetProperty="Height"
                        From="0"
                        To="{Binding Data.CustomControlProperty, Source={StaticResource TemplatedParentProxy}}"
                        Duration="0:0:5"
                        />
                </Storyboard>

死胡同

在排除了TemplateBinding{RelativeSource TemplatedParent} 之后,我的下一个猜测是将RootGrid.Tag 绑定到CustomControlProperty 并使用To="{Binding Tag, ElementName=RootGrid}"。那没有用。虽然智能感知在 XAML 设计器中知道 RootGrid,但 Binding 在运行时找不到 RootGrid

<DoubleAnimation
    Storyboard.TargetName="someElement"
    Storyboard.TargetProperty="Height"
    From="0"
    To="{Binding Tag, ElementName=RootGrid, PresentationTraceSources.TraceLevel=High}"
    Duration="0:0:1"
    />

调试跟踪:

System.Windows.Data Warning: 67 : BindingExpression (hash=15221148): Resolving source 
System.Windows.Data Warning: 69 : BindingExpression (hash=15221148): Framework mentor not found
System.Windows.Data Warning: 67 : BindingExpression (hash=15221148): Resolving source  (last chance)
System.Windows.Data Warning: 69 : BindingExpression (hash=15221148): Framework mentor not found
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=Tag; DataItem=null; target element is 'DoubleAnimation' (HashCode=44950942); target property is 'To' (type 'Nullable`1')

“管理 FrameworkElement 或 FrameworkContentElement”爵士乐也是所有其他方法的基本问题。这就是绑定代理的用武之地:资源查找不受视觉树父链内容的限制。

【讨论】:

  • 我试过这个,第一次尝试看起来不错。我会将这个答案标记为正确:)
【解决方案2】:

编辑我意识到我的答案根本行不通。

查看此相关讨论https://social.msdn.microsoft.com/Forums/vstudio/en-US/027c364f-5d75-424f-aafd-7fb76b10b676/templatebinding-on-storyboard?forum=wpf

[...] ColorAnimationTo 属性和 From 属性不能是 绑定,因为这些属性需要被冻结 (不可更改)以使动画正常工作。

所以请使用特定的颜色来代替绑定。

这表明某些动画元素不应该通过动态属性进行更改。我实际上不知道这适用于所有动画还是仅适用于特定子集。

因此,考虑到@EdPlunkett 的回答,可能值得调查一下,后续的属性更改是否真的无误地反映在动画中。


您应该使用{TemplateBinding CustomControlProperty} 进行单向绑定或使用{Binding RelativeSource={RelativeSource TemplatedParent},Path=CustomControlProperty} 如果您需要更复杂的绑定,而不是尝试通过其他方式找到模板化控件。

【讨论】:

  • “这表明某些动画元素不应该通过动态属性进行更改” -- 我自己不这么认为;如果设计者不辞辛劳地让它成为一个可写的依赖属性,他们不反对它成为一个绑定目标。并且在我的答案中测试了代码并发现它可以正常工作而没有奇怪或错误,我不会出汗。
  • 我也尝试了您的第一个解决方案。但是没有足够的时间在这里发布我的结果,对不起。不管怎么说,多谢拉。我现在就试试@Ed Plunkett 的回答。
猜你喜欢
  • 1970-01-01
  • 2013-10-07
  • 2010-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多