user2936676
user2936676

Reputation: 73

WPF Communication between User Controls

I'm trying to find the best way to communicate between two User Controls. I have a main XAML window which contains two User Controls which in turn contain various controls. The Code behind of each User Control simply sets the DataContext to a View Model that is associated to it. The View Model contains objects that are bound to the controls. What I'd like to do is capture when a list box in User Control 1 changes selection, the new selected item be displayed in an edit box in User Control 2. As I'm using View Models I can't declare Dependency Properties so I was wondering what is the accepted way to perform this? I've attached some basic code to show how I'm setting the controls.

Main Window XAML

<Window x:Class="CommsTest.View.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:CommsTest.View"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <local:UserControl1 />
    <local:UserControl2 />
</Grid>

UserControl1 XAML

<UserControl x:Class="CommsTest.View.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>
    <ComboBox Height="23" HorizontalAlignment="Left" Margin="50,110,0,0" Name="comboBox1" VerticalAlignment="Top" Width="199" ItemsSource="{Binding Combo1}" />
</Grid>

UserControl1ViewModel.cs

class UserControl1ViewModel
{
    private ObservableCollection<string> combo1 = new ObservableCollection<string>();

    public ObservableCollection<string> Combo1
    {
        get { return combo1; }
    }
}

UserControl2.XAML

<UserControl x:Class="CommsTest.View.UserControl2"
         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>
    <TextBox Height="23" HorizontalAlignment="Left" Margin="63,84,0,0" Name="textBox1" VerticalAlignment="Top" Width="170" Text="{Binding Path=Text1}" />
</Grid>

UserControl2ViewModel.cs

class UserControl2ViewModel
{
    private string text1;

    public string Text1
    {
        get { return text1; }
        set { text1 = value; }
    }
}

How do I get UserControl2.Text1 to be the selected value of UserControl2.Combo1? Thanks

Upvotes: 5

Views: 8253

Answers (3)

Kumareshan
Kumareshan

Reputation: 1341

I would suggest you, to have only one ViewModel and bind the DataContext to MainWindow.xaml, instead of doing it to each UserControl.

You should also implement INotifyPropertyChanged in your ViewModel to notify the UI whenever you change the value from the code or ViewModel.

Upvotes: 1

Sheridan
Sheridan

Reputation: 69985

While I understand that you are asking how to communicate between UserControls, I would suggest that the answer is to communicate between the view models. This can be easily achieved using delegate objects. In general, you'd need to have a parent view model that is common to the two child view models.

I recently answered a similar question, so I won't duplicate answers. Instead, I would ask you to take a look at the answer from the Passing parameters between viewmodels post here on StackOverflow which explains the solution with code examples.


UPDATE >>>

When I said that you need a common parent to your child view models, I don't mean anything to do with inheritance. I just mean that the parent holds a variable instance of each of the child view models... the parent instantiates the child view models.

Instead of creating the view model instance in the view code behind, you can do it in the parent view model and connect the view models to the views like this:

In Resources:

<DataTemplate DataType="{x:Type ViewModels:MainViewModel}">
    <Views:MainView />
</DataTemplate>
...
<DataTemplate DataType="{x:Type ViewModels:UsersViewModel}">
    <Views:UsersView />
</DataTemplate>

Then you just need to display an instance of the view model and the appropriate view will be displayed:

In ParentView:

<ContentControl Content="{Binding ViewModel}" />

In ParentViewModel:

public BaseViewModel ViewModel { get; set; } // Implement INotifyPropertyChanged

Then when you want to display a new view:

ViewModel = new UsersViewModel();

If your child views do not have a BaseViewModel and/or are not interchangable, then you could just add a property for each of them:

public MainViewmodel MainViewModel { get; set; } // Implement INotifyPropertyChanged
public UsersViewmodel UsersViewModel { get; set; } // properly for these properties

Either way, you'll need access to these view models from the parent view if you are going to be able to 'connect them together' with handlers.

Upvotes: 6

nvoigt
nvoigt

Reputation: 77364

Maybe you should think about your self-imposed restriction of not having dependency properties in user controls. MVVM is nice for the overal architecture, but you can overdo it if you put it into every class and control you plan to do.

If your user controls are just controls for the user, they should behave as such. I have never had to communicate with a TextBoxViewModel or ButtonViewModel, those are controls I simply use. Maybe yours is simple, too and does not need it's own viewmodel. Then you could communicate by using dependency properties as all other controls do.

Upvotes: 0

Related Questions