shadox
shadox

Reputation: 3709

WPF Data binding with ResourceDictionary MVVM

I'm trying to bind a View with a ViewModel within ResourceDictionary but it does not work.

The application is very simple window with 2 textboxes. When I type text to textbox1, atutomatically, textbox2 must get the same text. Of course my textboxes from the View have to be binded to my properties in ViewModel.

I'm new to WPF and the way I started to bind Views and ViewModels was in the codebehind of a View:

DataContext = new MyViewModel();

Now I'm trying to achieve a cleaner separation. My code is

App.xaml:

<Application x:Class="NavigationCleanBinding.App"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         StartupUri="/Views/MainWindowView.xaml">
    <Application.Resources>
        <ResourceDictionary Source="MainResourceDictionary.xaml" />
    </Application.Resources>
</Application>

MainResourceDictionary.xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xamlpresentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Views="clr-namespace:NavigationCleanBinding.Views"
    xmlns:ViewModels="clr-namespace:NavigationCleanBinding.ViewModels">

    <DataTemplate DataType="{x:Type ViewModels:MainWindowViewModel}">
        <Views:MainWindowView />
    </DataTemplate>

</ResourceDictionary>

MainWindowView.xaml:

<Window x:Class="NavigationCleanBinding.Views.MainWindowView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">

<Grid>
    <TextBox Height="23" HorizontalAlignment="Left" Margin="61,14,0,0" 
             Name="textBox1" VerticalAlignment="Top" Width="120" 
             Text="{Binding TestData, Mode=TwoWay,
             UpdateSourceTrigger=PropertyChanged}"/>
    <Label Content="Test:" Height="28" HorizontalAlignment="Left" Margin="12,12,0,0"
      Name="label1" VerticalAlignment="Top" Width="43" />
    <Label Content="Result:" Height="28" HorizontalAlignment="Left" Margin="10,46,0,0"
      Name="label2" VerticalAlignment="Top" />

    <TextBox Height="23" HorizontalAlignment="Left" Margin="61,48,0,0"
             Name="textBox2" VerticalAlignment="Top" Width="120" 

             Text="{Binding TestData, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
    </Grid>
</Window>

MainWindowViewModel:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NavigationCleanBinding.ViewModels
{
    class MainWindowViewModel
    {
        private String _testData;
        public String TestData
        {
            get { return _testData; }
            set { _testData = value; }
        }

        private MainWindowViewModel()
        {
            _testData = null;
        }
    }
}

UPDATE:

I changed property TestData to this:

public String TestData
    {
        get { return _testData; }
        set
        { 
            _testData = value;
            OnPropertyChanged("TestData");

        }
    }

And implemened the INotifyPropertyChanged like this:

public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(String propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

Upvotes: 5

Views: 11427

Answers (3)

Kamolas81
Kamolas81

Reputation: 549

Your ViewModel must implement the interface INotifyPropertyChanged and raise a PropertyChanged event when any bound property value changes, so that your view can know that changes occurred.

Upvotes: 1

TheZenker
TheZenker

Reputation: 1730

so user1064519 was on the right track:

  • the View needs to be a UserControl, not a Window, as it is hosted in the MainWindow
  • the ViewModel needs to be loaded into the MainWindow, this is what triggers the DataTemplate to be discovered and loaded.

    <Window x:Class="WpfTemplateBootstrap.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfTemplateBootstrap"
        Title="MainWindow" Height="350" Width="525">
        <ContentControl>
            <ContentControl.Content>
                <local:MainWindowViewModel />
            </ContentControl.Content>
        </ContentControl>
    

After that you should be up and running. I have posted an in-depth example here: wpf bootstrapping datatemplates--the chicken and the egg

Upvotes: 4

user1064519
user1064519

Reputation: 2190

DataTemplate sholudnt contain window, it can contains any kind of control.

DataTemplate :

 <DataTemplate DataType="{x:Type ViewModels:MainWindowViewModel}">
        <Views:MainWindowView />
 </DataTemplate>

UserControl :

    <UserControl x:Class="NavigationCleanBinding.Views.MainView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="350" Width="525">

<Grid>
    <TextBox Height="23" HorizontalAlignment="Left" Margin="61,14,0,0" 
             Name="textBox1" VerticalAlignment="Top" Width="120" 
             Text="{Binding TestData, Mode=TwoWay,
             UpdateSourceTrigger=PropertyChanged}"/>
    <Label Content="Test:" Height="28" HorizontalAlignment="Left" Margin="12,12,0,0"
      Name="label1" VerticalAlignment="Top" Width="43" />
    <Label Content="Result:" Height="28" HorizontalAlignment="Left" Margin="10,46,0,0"
      Name="label2" VerticalAlignment="Top" />

    <TextBox Height="23" HorizontalAlignment="Left" Margin="61,48,0,0"
             Name="textBox2" VerticalAlignment="Top" Width="120" 

             Text="{Binding TestData, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
    </Grid>
</UserControl>

Window :

 <Window x:Class="NavigationCleanBinding.Views.MainWindowView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">

<ContentControl Content={Binding}/>
</Window>

Upvotes: 1

Related Questions