Krystian Kuśmierek
Krystian Kuśmierek

Reputation: 43

MVVM uwp UserControl with VM as DataTemplate

I'm trying to create an app in UWP using MVVM pattern. It's possible that usercontrol which is a DataTemplate for items in Listbox would have his own VM.

Here is part of MainPage.xaml

 <ListBox Name="ListBox1" ItemsSource="{Binding Components}">
            <ListBox.ItemTemplate >
                <DataTemplate x:DataType="vm:ComponentUserControlViewModel"  >
                    <local:ComponentUserControl />
                </DataTemplate>
            </ListBox.ItemTemplate>
 </ListBox>

MainPageVM contains:

public ObservableCollection<Component> Components

For now it's my UserControl

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.RowDefinitions>
        <RowDefinition Height="*"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
    <TextBox Text="{Binding Id}" Grid.Row="0"></TextBox>
    <TextBox Text="{Binding Name}" Grid.Row="1"></TextBox>

</Grid>

VM:

    public class ComponentUserControlViewModel : ViewModelBase
{
    private string _componentId;
    private string _componentName;

    public ComponentUserControlViewModel()
    {
    }

    public string Id
    {
        get { return _componentId; }
        set
        {
            SetProperty(ref _componentId, value);
        }
    }
    public string Name
    {
        get { return _componentName; }
        set
        {
            SetProperty(ref _componentName, value);
        }
    }

What I want is for e.g. If I change Id property in my UI the view model Id property will changed too.

Upvotes: 4

Views: 2520

Answers (1)

P&#233;ter Bozs&#243;
P&#233;ter Bozs&#243;

Reputation: 1328

What Kris stated is true, you need dependency properties to achieve what you want.

In short, you can have two types of properties: the good old properties like you have in your ViewModel, Id and Name, and dependency properties. (Of course there are attached properties too, but conceptually they are the same as dependency properties.) The main difference between these two types of properties is that while both types can be targets to a data binding, only dependency properties can be the source of a data binding. That's right what you need.

So to solve your problem, we'll need a dependency property, defined in the code-behind of your control. Let's call this property 'Component', like Kris does it in his answer:

public static readonly DependencyProperty ComponentProperty = DependencyProperty.Register(
    "Component",
    typeof(ComponentUserControlViewModel), 
    typeof(ComponentUserControl), 
    new PropertyMetadata(null));
    
public ComponentUserControlViewModel Component
{
    get { return (ComponentUserControlViewModel) GetValue(ComponentProperty); }
    set { SetValue(ComponentProperty, value); }
}
    

Now if you change your binding on your UserControl to these (Note the Mode=OneWay, x:Bind is OneTime by default! More about it here.):

<TextBox Text="{x:Bind Component.Id, Mode=OneWay}" Grid.Row="0" />
<TextBox Text="{x:Bind Component.Name, Mode=OneWay}" Grid.Row="1" />

And replace your DataTemplate-s content with the one Kris supplied:

<local:ComponentUserControl Component="{Binding}" />

The magic will happen and all of this will work! :) If you have any more questions on the matter, please check this official overview of dependency properties.

Upvotes: 5

Related Questions