MVVM + UserControl + Dependency Property

11,067

Solution 1

Alright, after hours of googling it appears that the "correct" approach to this is not to do it at all. The general approach is to keep the data in your MainViewModel and not use an additional ViewModel for the UserControl (which I find a little ... well .. not so good). The main problem is that there is no easy mechanism to get the Data from the Dependency Property to the ViewModel.

For printing, I have now gone back to doing it purely in code.

Solution 2

You would usually bind the UserControl's property to the ViewModel property. A two-way binding would work in both directions, from ViewModel to View and vice versa.

<Window x:Class="TestApplication.MainWindow" ...>
    <Window.DataContext>
        <local:MyViewModel/>
    </Window.DataContext>
    <Grid>
        <local:UcTest SpecialText="{Binding MyViewModelProperty, Mode=TwoWay}"/>
    </Grid>
</Window>

To directly access the ViewModel object in the above example, you could simply cast the UserControl's DataContext property to the ViewModel type. The DataContext is inherited from the MainWindow.

var viewModel = DataContext as MyViewModel;
var property = viewModel.MyViewModelProperty;

You could of course also directly assign a specialized ViewModel instance to the UserControl's DataContext:

<local:UcTest SpecialText="{Binding MyViewModelProperty, Mode=TwoWay}"/>
    <local:UcTest.DataContext>
        <local:UserControlViewModel/>
    </local:UcTest.DataContext>
</local:UcTest>

or you may create the ViewModel instance as a resource in a resource dictionary and assign the DataContext like this

<local:UcTest DataContext="{StaticResource MyUserControlViewModel}"
              SpecialText="{Binding MyViewModelProperty, Mode=TwoWay}"/>
Share:
11,067
Tom L.
Author by

Tom L.

Working for a local company focused on electronics production mainly as a software engineer.

Updated on June 11, 2022

Comments

  • Tom L.
    Tom L. about 2 years

    Alright, this is somewhat related to this question: WPF Printing multiple pages from a single View Model

    I tried to follow the advice given there but now I am stuck.

    My application uses a MainView.xaml and the appropriate MainViewViewModel.cs, I am using MVVM Light in the background.

    Now - according to the post - it seems I have to do the following:

    • Create a user control
    • Expose some properties from the user control
    • Make sure the view model shows these properties

    The idea is clear but I am stuck when trying to notify each other.

    My user control (UcTest.xaml) exposes a Dependency Property:

    public string SpecialText
    {
        get { return (string)GetValue(SpecialTextProperty); }
        set
        {
            SetValue(SpecialTextProperty, value);
    
        }
    }
    
    // Using a DependencyProperty as the backing store for SpecialText.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SpecialTextProperty =
        DependencyProperty.Register("SpecialText", typeof(string), typeof(UcTest), new PropertyMetadata(new PropertyChangedCallback(SpecialTextChangedPropertyCallback)));
    
    private static void SpecialTextChangedPropertyCallback(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        // Do something
        Debug.WriteLine("Ffgdgf");
    }
    

    Alright, so I do now have a user control which has some dependency properties. Yet, these properties are completely separated from my ViewModel properties (those are the ones which shall be displayed).

    So basically I have two possibilities:

    • How can I now tell my ViewModel for the UserControl that some properties have changed?
    • Is there a possibility to forget about the dependency properties and access the view model directly?

    Additional info #1: I have uploaded a (simple) example of what I am trying to do here: Example Project. I would like to change the value of the label in UserControl1 (via the binding property in the ViewModel for UserControl1) from my MainViewViewModel.

  • Tom L.
    Tom L. over 11 years
    Hm, I think I may misunderstand you. The problem is that the UserControl has its own ViewModel which I would like to bind to. Or do you think that it would be better to keep the properties in the MainViewModel and just use the UserControl without its own ViewModel?
  • Clemens
    Clemens over 11 years
    That depends on your application design. Both are valid solution. You could as well directly assign the UserControl's DataContext property.
  • Tom L.
    Tom L. over 11 years
    Hm, no .. I don't really understand this. Would you mind posting an example? Because as soon as I change the DataContext for the UserControl to the UserControlViewModel I cannot assign any more variables as the UserControl doesn't know about these properties. How can I assign something to "SpecialText" if SpecialText is no DependencyProperty?
  • Clemens
    Clemens over 11 years
    See my edit. What do you mean by "how can I assign something to "SpecialText" if SpecialText is no DependencyProperty?". SpecialText is a dependency property, you have it designed it that way.
  • Tom L.
    Tom L. over 11 years
    Yes (oh this is so hard to explain). the main point is that the Dependency Property "Special Text" is decoupled from the ViewModel. I have uploaded a small example (link in my main post) to maybe demonstrate what I mean.
  • bytecode77
    bytecode77 over 7 years
    This may apply to cases where you separate tab items into user controls. But what about general controls, like a file browser, which are displayed multiple times?
  • TK-421
    TK-421 over 6 years
    @Tom L. in your situation, the best I have been able to come up with is to not set a data context in the user control, then on windows load save the passed properties from the DP to variables, then set the context to a new instance of your VM. Then set the proper properties in the VM and continue on. It's not ideal, but it does get the job done. I wish in the metadata of the DP you could specify in what context to get the bindings.