1

I want a custom WPF user control with one attribute/property, and implementers of that user control must be able to bind their value to it.

See this example: http://www.codeproject.com/Articles/42203/How-to-Implement-a-DependencyProperty

Instead of <local:MyUserControl Caption="My First Dependency Property Example" /> I want something like <local:MyUserControl Caption="{Binding MyCaption}" /> where MyCaption is a string property in the DataContext viewmodel class. However, whenever I change the MyCaption value, it is not reflected in the user control...

I've got this own piece of code where I test the same principle, but the text is never updated:

MainWindow.xaml.cs:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        private string _MyFirstName;
        public string MyFirstName
        {
            get
            {
                return _MyFirstName;
            }
            set
            {
                _MyFirstName = value;
                RaisePropertyChanged("MyFirstName");
            }
        }

        public MainWindow()
        {
            InitializeComponent();
        }

        private void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            //this.Klaas.SetValue(NameControl.FirstNameProperty, "Mike");
            MyFirstName = "Mike";
        }
    }
}

MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:me="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525"
        DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <me:NameControl x:Name="Klaas" FirstName="{Binding MyFirstName}" Grid.Row="0"/>
        <Button Grid.Row="1" Click="Button_Click">Pick a name</Button>
    </Grid>
</Window>

NameControl.xaml.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for NameControl.xaml
    /// </summary>
    public partial class NameControl : UserControl
    {
        public static readonly DependencyProperty FirstNameProperty = DependencyProperty.Register(
            "FirstName", 
            typeof(string),
            typeof(NameControl),
            new PropertyMetadata("NoName", OnFirstNamePropertyChanged));

        public string FirstName
        {
            get
            {
                return (string)GetValue(FirstNameProperty);
            }
            set
            {
                SetValue(FirstNameProperty, value);
            }
        }

        private static void OnFirstNamePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            NameControl source = d as NameControl;
            // Do something...
        }

        public NameControl()
        {
            InitializeComponent();
        }
    }
}

NameControl.xaml

<UserControl x:Class="WpfApplication1.NameControl"
         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" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300"
         DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <TextBlock Grid.Column="0" Width="100" Text="{Binding FirstName}" />
    <TextBlock Grid.Column="1" Width="100" Text="{Binding LastName}" />
</Grid>
</UserControl>

1 Answer 1

3

When you do

<UserControl ... DataContext="{Binding RelativeSource={RelativeSource Self}}">

you effectively overwrite DataContext that would normally be passed to your control from visual tree and you change binding context for bindings within NameControl control. I would suggest to remove that and do that per binding

<TextBlock ... Text="{Binding FirstName, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
<TextBlock ... Text="{Binding LastName, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />

or to make it simpler give UserControl some name and use it for bindings within your control

<UserControl... x:Name="myUserControl">
   <Grid>
      <Grid.ColumnDefinitions>
         <ColumnDefinition Width="Auto"/>
         <ColumnDefinition Width="Auto"/>
      </Grid.ColumnDefinitions>
      <TextBlock Grid.Column="0" Width="100" Text="{Binding FirstName, ElementName=myUserControl}" />
      <TextBlock Grid.Column="1" Width="100" Text="{Binding LastName, ElementName=myUserControl}" />
   </Grid>
</UserControl>
Sign up to request clarification or add additional context in comments.

1 Comment

Yesss, now it works! Thanks so much. UK saved my day!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.