简体   繁体   中英

How to bind a UserControl's property to a property?

I'd like to set a property of a re-defined UserControl (for example its background color) to a property of the class. For example. If I define the background of a Button to a property ( <Button x:Name="myButton" Background="{Binding ColorName}"/> ), it works fine. However, if I do the same for a re-defined UserControl ( <local:MyUserControl Background="{Binding Path=ColorName}"/> ), it does not.

What's funny though, is that, if I do <local:MyUserControl Background="{Binding Background, ElementName=myButton}"/> , it works perfectly fine.

Could I have some help on that? I must be missing something.

Thanks!

EDIT

Here is all the code. The setting of the background color worked fine. What solved this was to set properly the MainWindow.DataContext and to remove the DataContext = this in MyUserControl.xaml.cs . Setting Color as a DependencyProperty is also useful to be able to change the Color setting in a later execution of the code. Nonetheless, while removing DataContext=this in MyUserControl.xaml.cs , the {Binding TextContent} does not work and needs to be replaced by {Binding TextContent, RelativeSource={RelativeSource AncestorType=c:MyUserControl}} .

MainWindow.xaml

<Window x:Class="BindingBug.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:c="clr-namespace:BindingBug"
        Title="MainWindow" Height="350" Width="525"
        DataContext="{Binding RelativeSource={RelativeSource Self}}">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <Button Background="{Binding Path=Color}"
                Width="250" 
                Height="30"
                Content="I am bound to be RED!"
                Grid.Row="0"
                x:Name="myButton"/>
        <c:MyUserControl Background="{Binding Background, ElementName=myButton}"
                Width="250" 
                Height="30"
                Content="I am bound to be RED!"
                Grid.Row="1"/>
        <c:MyUserControl Background="{Binding Path=Color}"
                Width="250" 
                Height="30"
                Content="I am bound to be RED!"
                Grid.Row="2"/>
    </Grid>
</Window>

MainWindow.xaml.cs

using System.Windows;
using System.Windows.Media;

namespace BindingBug
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Color = Brushes.Red;
        }

        public static readonly DependencyProperty ColorProperty = DependencyProperty.Register("Color", typeof(Brush), typeof(MainWindow));

        public Brush Color
        {
            get
            {
                return (Brush)GetValue(ColorProperty);
            }
            set
            {
                SetValue(ColorProperty, value);
            }
        }
    }
}

MyUserControl.xaml

<UserControl x:Class="BindingBug.MyUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:c="clr-namespace:BindingBug"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="1*" />
            <RowDefinition Height="2*" />
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" 
                   FontSize="13"
                   Text="{Binding TextContent, RelativeSource={RelativeSource AncestorType=c:MyUserControl}}"
                   VerticalAlignment="Center"/>
    </Grid>
</UserControl>

MyUserControl.xaml.cs

using System.Windows;
using System.Windows.Controls;

namespace BindingBug
{
    /// <summary>
    /// Interaction logic for NumberDataHolder.xaml
    /// </summary>
    public partial class MyUserControl : UserControl
    {
        public MyUserControl()
        {
            InitializeComponent();
        }

        public static readonly DependencyProperty TextContentProperty = DependencyProperty.Register("TextContent", typeof(string), typeof(MyUserControl));

        public string TextContent
        {
            get
            {
                return (string)GetValue(TextContentProperty);
            }
            set
            {
                SetValue(TextContentProperty, value);
            }
        }
    }
}

EDIT 2

I tried to acheive the same results without having to declare the whole Text="{Binding TextContent, RelativeSource={RelativeSource AncestorType=c:MyUserControl}}" inside TextBlock . So, following @KeithStein advice, I placed DataContext="{Binding RelativeSource={RelativeSource Self}}" inside MyUserControl and only kept Text="{Binding TextContent}" inside TextBlock . That, however cancels the effect of setting Background="{Binding Path=Color}" in MainWindow.xaml . Any idea why? Is there another possibility to set Background="{Binding Path=Color}" in MainWindow.xaml and to only keep Text="{Binding TextContent}" inside TextBlock ?

MainWindow.xaml

<Window x:Class="BindingBug.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:c="clr-namespace:BindingBug"
        Title="MainWindow" Height="350" Width="525"
        DataContext="{Binding RelativeSource={RelativeSource Self}}">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <Button Background="{Binding Path=Color}"
                Width="250" 
                Height="30"
                Content="I am bound to be RED!"
                Grid.Row="0"
                x:Name="myButton"/>
        <c:MyUserControl Background="{Binding Background, ElementName=myButton}"
                Width="250" 
                Height="30"
                Content="I am bound to be RED!"
                Grid.Row="1"/>
        <c:MyUserControl Background="{Binding Path=Color}"
                Width="250" 
                Height="30"
                Content="I am bound to be RED!"
                Grid.Row="2"/>
    </Grid>
</Window>

MainWindow.xaml.cs

using System.Windows;
using System.Windows.Media;

namespace BindingBug
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Color = Brushes.Red;
        }

        public static readonly DependencyProperty ColorProperty = DependencyProperty.Register("Color", typeof(Brush), typeof(MainWindow));

        public Brush Color
        {
            get
            {
                return (Brush)GetValue(ColorProperty);
            }
            set
            {
                SetValue(ColorProperty, value);
            }
        }
    }
}

MyUserControl.xaml

<UserControl x:Class="BindingBug.MyUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:c="clr-namespace:BindingBug"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
        DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="1*" />
            <RowDefinition Height="2*" />
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" 
                   FontSize="13"
                   Text="{Binding TextContent}"
                   VerticalAlignment="Center"/>
    </Grid>
</UserControl>

MyUserControl.xaml.cs

using System.Windows;
using System.Windows.Controls;

namespace BindingBug
{
    /// <summary>
    /// Interaction logic for NumberDataHolder.xaml
    /// </summary>
    public partial class MyUserControl : UserControl
    {
        public MyUserControl()
        {
            InitializeComponent();
        }

        public static readonly DependencyProperty TextContentProperty = DependencyProperty.Register("TextContent", typeof(string), typeof(MyUserControl));

        public string TextContent
        {
            get
            {
                return (string)GetValue(TextContentProperty);
            }
            set
            {
                SetValue(TextContentProperty, value);
            }
        }
    }
}

This answer developed gradually through back and forth comments with OP. To summarize:

  • Use a Brush -type dependency property for your color. Brush because that is the type of the Background property that you want to bind to, and a dependency property so that updates of the property trigger any bindings to refresh.
  • When binding inside a Window or UserControl , you need to set DataContext , which is essentially the default sourced used by bindings.
    • For a Window , add DataContext="{Binding RelativeSource={RelativeSource Self}}" to the opening tag. This sets the default source for all controls contained within to the Window itself.
    • For a UserControl , add the following to the outer-most panel of said control: DataContext={Binding RelativeSource={RelativeSource AncestorType=UserControl}} ( UserControl can be replaced with the name of your particular control, ie c:MyUserControl ). This tells everything inside that root panel to use the UserControl as the default source. You can't use RelativeSource Self in this case, because then instances of the MyUserControl will bind to themselves when placed inside Window s, instead of inheriting the Window 's DataContext .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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