简体   繁体   English

从ContentControl绑定前景

[英]Binding Foreground from ContentControl

I have a binding problem with WindowsPhone 8 and a ControlTemplate. 我在WindowsPhone 8和ControlTemplate上遇到绑定问题。 Here is an example: 这是一个例子:

<UserControl.Resources>
<Style TargetType="Button">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <ContentControl x:Name="ContentContainer" Foreground="Red" Content="{TemplateBinding Content}"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
</UserControl.Resources>

<Button>
    <Button.Content>
        <TextBlock Text="123"/>
    </Button.Content>
<Button>

I would like to use in my Button.Content the foreground "Red" I defined in the ContentContainer. 我想在我的Button.Content中使用在ContentContainer中定义的前景“红色”。 But nothing works... The goal is to change the ContentContainer foreground in a VisualState in my Style. 但是没有任何效果。目标是在我的样式的VisualState中更改ContentContainer前景。 Can anyone help me? 谁能帮我?

You should do : 你应该做 :

<Button Content="123"/>

Instead of putting a TextBlock. 而不是放置一个TextBlock。

However if you want to keep the TextBlock anyway, the you should do : 但是,如果您仍然想保留TextBlock,则应该执行以下操作:

<Style TargetType="TextBlock">
            <Setter Property="Foreground">
                <Setter.Value>
                    red
                </Setter.Value>
            </Setter>
        </Style>

Managed to pull this off with a behavior. 设法通过行为来实现这一目标。 It's a pretty complicated solution, but it's the only one i found working : 这是一个非常复杂的解决方案,但它是我发现的唯一可行的解​​决方案:

First, some Util stuff : 首先,一些实用工具:

public static class IEnumerableExt
{
    public static T FirstOrDefault<T>(this IEnumerable<T> source)
    {
        if (source.Count() > 0)
            return source.ElementAt(0);
        return default(T);
    }
}

and ... 还有...

public static class DependencyObjectExt
{
        public static DependencyObject GetChild(this DependencyObject @this, int childIndex)
        {
            return VisualTreeHelper.GetChild(@this, childIndex);
        }

        public static IEnumerable<DependencyObject> GetChildren(this DependencyObject @this)
        {
            for(int i = 0; i < VisualTreeHelper.GetChildrenCount(@this); i++)
            {
                yield return @this.GetChild(i);
            }
        }

        public static IEnumerable<T> FindChildrenOfType<T>(this DependencyObject @this) where T : DependencyObject
        {
            foreach(var child in @this.GetChildren())
            {
                if(child is T)
                {
                    yield return child as T;
                }
            }
        }

        public static IEnumerable<T> FindDescendantsOfType<T>(this DependencyObject @this) where T : DependencyObject
        {
            IEnumerable<T> result = Enumerable.Empty<T>();

            foreach(var child in @this.GetChildren())
            {
                if(child is T)
                {
                    result = result.Concat(child.ToEnumerable().Cast<T>());
                }
                result = result.Concat(child.FindDescendantsOfType<T>());
            }

            return result;
        }
}

Now, let's define a behavior that does the binding : 现在,让我们定义一个执行绑定的行为:

public class ContentControlForegroundBindingBehavior : Behavior<Control>
{
    public static DependencyProperty ParentProperty =
        DependencyProperty.Register("Parent", typeof(Control),
            typeof(ContentControlForegroundBindingBehavior), new PropertyMetadata(null));

    public Control Parent
    {
        get { return (Control)this.GetValue(ParentProperty); }
        set { this.SetValue(ParentProperty, value); }
    }


    protected override void OnAttached()
    {
        base.OnAttached();

        AssociatedObject.Loaded += (sender, e) =>
        {
            if (Parent == null) return;

            var control = AssociatedObject as Control;
            if (control == null) return;


            var contentControl = Parent.FindDescendantsOfType<ContentControl>().FirstOrDefault();
            if (contentControl == null) return;

            control.SetBinding(Control.ForegroundProperty, new Binding()
            {
                NotifyOnSourceUpdated = true,
                Mode = BindingMode.OneWay,
                UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
                BindsDirectlyToSource = true,
                Path = new PropertyPath(Control.ForegroundProperty),
                Source = contentControl
            });
        };
    }
}

What this behavior does is bind the control's foreground to the foreground of the ContentControl found in the template of the specified parent. 此行为的作用是将控件的前景绑定到在指定父级模板中找到的ContentControl的前景。 This is how you use it (in xaml): 这是使用它的方式(在xaml中):

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
        xmlns:behaviors=" ---------- Your Behaviors Namespace ---------"

<Button x:Name="SomeName"
                Width="125"
                Height="30"
                Click="OnButtonClick"
                HorizontalAlignment="Left"
                VerticalAlignment="Top"
                Margin="50,54,0,0">
            <Button.Content>
                <controls:IconText Icon="SomeIcon.png"
                                   Text="SomeText">
                    <i:Interaction.Behaviors>
                        <behaviors:ContentControlForegroundBindingBehavior Parent="{Binding ElementName=SomeName}"/>
                    </i:Interaction.Behaviors>
                </controls:IconText>
            </Button.Content>
</Button>

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

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