7

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.

Community
  • 1
  • 1
Tom L.
  • 932
  • 2
  • 9
  • 30
  • 1
    That would mean that my UserControl would need to implement INotifyPropertyChanged which is basically what my ViewModel should do. – Tom L. Mar 02 '13 at 19:11

2 Answers2

5

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}"/>
Clemens
  • 123,504
  • 12
  • 155
  • 268
  • 1
    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? – Tom L. Mar 02 '13 at 16:11
  • That depends on your application design. Both are valid solution. You could as well directly assign the UserControl's DataContext property. – Clemens Mar 02 '13 at 16:44
  • 1
    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? – Tom L. Mar 02 '13 at 16:50
  • 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. – Clemens Mar 02 '13 at 17:20
  • 1
    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. – Tom L. Mar 02 '13 at 17:29
5

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.

Tom L.
  • 932
  • 2
  • 9
  • 30
  • 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? – bytecode77 Dec 10 '16 at 19:55
  • @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. – TK-421 Oct 07 '17 at 05:06