简体   繁体   English

绑定到VisualStateManager中的Control属性

[英]Bind to Control's Property inside VisualStateManager

I searched for this Problem on Stackoverflow, but in my opinion the other Posts do not cover this question. 我在Stackoverflow上搜索了这个问题,但在我看来,其他帖子没有涵盖这个问题。

In my Custom Control i am using a Visual State Manager. 在我的自定义控件中,我使用的是Visual State Manager。 Inside the Visual State Manager there is an Animation that Animates the Height of an Element. 在可视状态管理器内部有一个动画,可以动画元素的高度。 When i try to bind to the Controls Properties i get following Error on StartUp: 当我尝试绑定到控件属性时,我在启动时遇到以下错误:

Additional information: Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType=MyNameSpace.MyControl, AncestorLevel='1''. 附加信息:找不到引用'RelativeSource FindAncestor,AncestorType = MyNameSpace.MyControl,AncestorLevel ='1'的绑定源。 BindingExpression:Path=ActualHeight; BindingExpression:路径=的ActualHeight; DataItem=null; 的DataItem = NULL; target element is 'DoubleAnimation' (HashCode=562002); target元素是'DoubleAnimation'(HashCode = 562002); target property is 'To' (type 'Nullable`1') target属性为'To'(类型'Nullable`1')

My Control looks like this: 我的控件看起来像这样:

<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" />
...

I tried all ways of Bindings, but it seems that the Animations always takes itself as Scope. 我试过Bindings的所有方法,但似乎Animations总是将自己视为Scope。

Thanks for your help again. 再次感谢您的帮助。

I was able to do this with a BindingProxy . 我能用BindingProxy做到这BindingProxy I find binding proxies to be nonintuitive. 我发现绑定代理是非直观的。 Sometimes they work on the first shot; 有时他们会在第一次拍摄时工作; this one took a little trial and error. 这个尝试了一点试验和错误。 Also, they're a little bit of a hail-mary workaround. 此外,他们是一个有点冰雹的解决方法。

XAML: 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# (stolen, not for the first time, from this answer ): C#(被盗,不是第一次, 从这个答案 ):

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));
}

Here's another variant of the XAML, in case you end up binding animation properties to more than one property of the templated parent: 这是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>

Blind Alleys 盲人小巷

After ruling out TemplateBinding and {RelativeSource TemplatedParent} , my next guess was to bind RootGrid.Tag to CustomControlProperty and use To="{Binding Tag, ElementName=RootGrid}" . 在排除TemplateBinding{RelativeSource TemplatedParent} ,我的下一个猜测是将RootGrid.Tag绑定到CustomControlProperty并使用To="{Binding Tag, ElementName=RootGrid}" That did not work. 那没用。 While intellisense knew about RootGrid in the XAML designer, the Binding couldn't find RootGrid at runtime: 虽然intellisense知道XAML设计RootGrid中的RootGrid ,但Binding在运行时找不到RootGrid

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

Debug trace: 调试跟踪:

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')

That "governing FrameworkElement or FrameworkContentElement" jazz is the essential problem with all of the other approaches as well. “管理FrameworkElement或FrameworkContentElement”爵士乐也是所有其他方法的基本问题。 That's where binding proxies come in: Resource lookup isn't limited by that visual tree parent chain stuff. 这就是绑定代理进入的地方:资源查找不受可视树父链的限制。

Edit I realized my answer doesn't work after all. 编辑我意识到我的答案毕竟不起作用。

See this related discussion https://social.msdn.microsoft.com/Forums/vstudio/en-US/027c364f-5d75-424f-aafd-7fb76b10b676/templatebinding-on-storyboard?forum=wpf 请参阅此相关讨论https://social.msdn.microsoft.com/Forums/vstudio/en-US/027c364f-5d75-424f-aafd-7fb76b10b676/templatebinding-on-storyboard?forum=wpf

[...] The To property and From property of ColorAnimation can't be bind with, because of those properties need to be frozen (unchangeable) for the animation to work. [...] ColorAnimationTo属性和From属性无法绑定,因为这些属性需要被冻结(不可更改)才能使动画ColorAnimation

So please use specific color to instead of binding. 所以请使用特定的颜色而不是绑定。

This suggests that some animation elements are not supposed to change via dynamic properties. 这表明一些动画元素不应该通过动态属性来改变。 I actually don't know whether this applies to all animations or just to a specific subset. 我实际上不知道这是适用于所有动画还是仅适用于特定子集。

So considering @EdPlunkett answer, it might be worth to investigate, whether subsequent property changes are actually reflected in the animation without errors. 因此,考虑到@EdPlunkett的答案,可能值得研究一下,后续的属性更改是否实际上反映在动画中而没有错误。


You should use {TemplateBinding CustomControlProperty} for one way binding or {Binding RelativeSource={RelativeSource TemplatedParent},Path=CustomControlProperty} if you need more binding complexity, instead of trying to find the templated control by other means. 如果需要更多绑定复杂性,则应使用{TemplateBinding CustomControlProperty}进行单向绑定或{Binding RelativeSource={RelativeSource TemplatedParent},Path=CustomControlProperty} ,而不是尝试通过其他方式查找模板化控件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM