Search code examples
wpfuser-controlsdependency-properties

DependencyProperty issues with respect to a UserControl and WPF Dialog


I've dumbed down the code as much as I could to try and get a working piece of code yet I'm still coming up short. Some advice would be appreciated.

I'm trying to get a DependencyProperty working, it's that simple and yet the data I'm setting on the main window isn't showing up in the user control.

In the MainWindow I'm setting the TextValue to "hi" in the xaml. TextValue is showing in the xaml up and compiling just fine so I'm pretty sure I have the DependencyProperty set right. Once the dialog is fully open I take a look in the debugger and my property TextValue is still null.

Am I missing setting the data context? Maybe I'm off base in what I'm looking to do.

Thanks for taking the time to figure out what I'm doing wrong.

My User Control is: UserControl1 Xaml:

<UserControl x:Class="WpfApplication1.UserControl1"
             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" 
             Loaded="UserControl_Loaded"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>

    </Grid>
</UserControl>

UserControl1.xaml.cs is:

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

        public static readonly DependencyProperty TextProperty = DependencyProperty.Register("TextValue", typeof(string), typeof(UserControl1));

        private string _tv;
        public string TextValue
        {
            get
            {
                return _tv;
            }
            set
            {
                _tv = value;
            }
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {

        }
    }
}

My calling window xaml is:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:usercontrols="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525"
        Loaded='Window_Loaded'>
    <Grid>
        <usercontrols:UserControl1 x:Name="usercontroltest1" TextValue="hi"/>
    </Grid>
</Window>

My calling window .cs is:

    namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {

        }
    }
}

Solution

  • The getter and setter of the "property wrapper" must call the GetValue and SetValue methods of the DependencyObject base class like shown below. Besides that, there is a naming convention that mandates that a dependency property's identifier field is named like the property plus a Property suffix. See Custom Dependency Properties for all the details.

    public static readonly DependencyProperty TextValueProperty =
        DependencyProperty.Register(
            nameof(TextValue), typeof(string), typeof(UserControl1));
    
    public string TextValue
    {
        get { return (string)GetValue(TextValueProperty); }
        set { SetValue(TextValueProperty, value); }
    }
    

    In order to access a UserControl's dependency property in its own XAML, you would typically use a RelativeSource Binding like this:

    <UserControl x:Class="WpfApplication1.UserControl1" ...>
        <Grid>
            <TextBlock Text="{Binding TextValue,
                              RelativeSource={RelativeSource AncstorType=UserControl}}" />
        </Grid>
    </UserControl>