Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF MVVM binding to DependencyProperty of a UserControl not working

I am trying to stick close to MVVM approach to building my WPF app and am running into a weird binding issue and feel like I'm missing something.

I have a user control (PluginsTreeView) which has a ViewModel (PluginsViewModel) driving it. PluginsTreeView exposes a public DependencyProperty of type string (DocumentPath). My MainWindow set's this property in XAML, but it doesn't seem to make it to my UserControl. I'm looking for some indication as to why this doesn't work.

PluginsTreeView.xaml.cs

public partial class PluginsTreeView: UserControl
{
    public PluginsTreeView()
    {
        InitializeComponent();
        ViewModel = new ViewModels.PluginsViewModel();
        this.DataContext = ViewModel;
    }

    public static readonly DependencyProperty DocumentPathProperty =
        DependencyProperty.Register("DocumentPath", typeof(string), typeof(PluginsTreeView), new FrameworkPropertyMetadata(""));


    public string DocumentPath
    {
        get { return (string)GetValue(DocumentPathProperty); }
        set 
        {
            //*** This doesn't hit when value set from xaml, works fine when set from code behind
            MessageBox.Show("DocumentPath"); 
            SetValue(DocumentPathProperty, value); 
            ViewModel.SetDocumentPath(value);
        }
    }
    ....
 }

MainWindow.xaml

My PluginsTreeView never gets the value 'test path' and I'm not sure why. I feel like I'm missing something fundamental here.

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Views="clr-namespace:Mediafour.Machine.EditorWPF.Views" x:Class="Mediafour.Machine.EditorWPF.MainWindow"
    xmlns:uc="clr-namespace:Mediafour.Machine.EditorWPF.Views"
    Title="MainWindow" Height="350" Width="600">
  <Grid>
    <uc:PluginsTreeView x:Name="atv" DocumentPath="from xaml" />
  </Grid>
</Window>

But, when I set the DependencyProperty from the code-behind of the MainWindow, it does seem to set the value correctly. I'm trying to figure out the difference here and why the code-behind approach works and setting the property in xaml doesn't.

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        MainWindowViewModel ViewModel = new MainWindowViewModel();
        this.DataContext = ViewModel;

        atv.DocumentPath = "from code behind";  //THIS WORKS!
     }
     ....
 }

Messing around with Snoop, I see that the value from XAML "from xaml" does make it into the property but my Set method in PluginsTreeView still never gets hit. The message box I have in there as a debug tool doesn't pop unless value is set from MainWindow code-behind.

like image 590
genus Avatar asked Nov 03 '22 13:11

genus


1 Answers

Apparently you should not add any logic to these properties setters, because they are only called when you set the property from code. If you set the property from XAML the SetValue() method is called directly. I've ended up registering a callback method and all works great now:

public static readonly DependencyProperty DocumentPathProperty = DependencyProperty.Register("DocumentPath", typeof(string), typeof(PluginsTreeView), new FrameworkPropertyMetadata("initial value", OnValueChanged));
like image 123
genus Avatar answered Nov 08 '22 04:11

genus