Mike
Mike

Reputation: 3284

Dependency Property From User Control - WPF

This might be a very silly question, but I'm trying to find out what is going on wrong with my code.

I have a user control with a button inside it. I have a DependencyProperty declared, which I'm binding to the content of the button inside the user control (yes, it's weird).

Now I'm using 2 instances of this user control inside my main xaml page, and the Dependency Property is bound to a property in my ViewModel. However, the binding fails during run time.

Question is - Why doesn't it work?

Code:

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:WpfApplication2="clr-namespace:WpfApplication2" Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <WpfApplication2:UserControl1 NewContent="{Binding CanEnableOne}" Grid.Row="0"/>
        <WpfApplication2:UserControl1 NewContent="{Binding CanEnableTwo}"  Grid.Row="1"/>
        <Button Grid.Row="2" Content="Enable Hello1" Click="OnClickedOne"/>
        <Button Grid.Row="3" Content="Enable Hello2" Click="OnClickedTwo"/>        
    </Grid>
</Window>


public partial class MainWindow : Window
{
    ViewModel vm = new ViewModel();
    Random r = new Random();
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = vm;
    }

    private void OnClickedOne(object sender, RoutedEventArgs e)
    {
        vm.CanEnableOne = r.Next(1,100).ToString();
    }

    private void OnClickedTwo(object sender, RoutedEventArgs e)
    {
        vm.CanEnableTwo = r.Next(1, 100).ToString();
    }
}

public class ViewModel : INotifyPropertyChanged
{
    private string _canEnableOne;
    public string CanEnableOne
    {
        get { return _canEnableOne; }

        set
        {
            if (_canEnableOne == value)
                return;
            _canEnableOne = value;
            InvokePropertyChanged("CanEnableOne");
        }
    }


    private string _canEnableTwo;
    public string CanEnableTwo
    {
        get { return _canEnableTwo; }

        set
        {
            if (_canEnableTwo == value)
                return;
            _canEnableTwo = value;
            InvokePropertyChanged("CanEnableTwo");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void InvokePropertyChanged(string e)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(e));
    }
}


<UserControl x:Class="WpfApplication2.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" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Button Content="{Binding NewContent}"></Button>    
    </Grid>
</UserControl>


public partial class UserControl1 : UserControl
{
    public UserControl1()
    {
        InitializeComponent();
    }

    public static readonly DependencyProperty NewContentProperty =
        DependencyProperty.RegisterAttached("NewContent",
                                                   typeof (string),
                                                   typeof (UserControl1), new PropertyMetadata(new PropertyChangedCallback(PropertyChanged)));

    private static void PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("Hello");
    }

    public string NewContent
    {
        get { return (string)GetValue(NewContentProperty); }
        set { SetValue(NewContentProperty, value); }
    }

}

Error:System.Windows.Data Error: 39 : BindingExpression path error: 'NewContent' property not found on 'object' ''ViewModel' (HashCode=23172649)'. BindingExpression:Path=NewContent; DataItem='ViewModel' (HashCode=23172649); target element is 'Button' (Name=''); target property is 'Content' (type 'Object')
System.Windows.Data Error: 39 : BindingExpression path error: 'NewContent' property not found on 'object' ''ViewModel' (HashCode=23172649)'. BindingExpression:Path=NewContent; DataItem='ViewModel' (HashCode=23172649); target element is 'Button' (Name=''); target property is 'Content' (type 'Object')

Upvotes: 0

Views: 670

Answers (1)

dowhilefor
dowhilefor

Reputation: 11051

Remember, {Binding} will default wise always take the DataContext as the source of the property. Thats why your code isn't working, NewContent is not a property in your ViewModel.

You want to change the source of your binding, to your UserControl, this is one way to do it:

<UserControl x:Class="WpfApplication2.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" 
             mc:Ignorable="d" 
             d:DesignHeight="300" 
             d:DesignWidth="300"
             x:Name="myControl">
    <Grid>
        <Button Content="{Binding ElementName=myControl, Path=NewContent></Button>    
    </Grid>
</UserControl>

Upvotes: 2

Related Questions