简体   繁体   中英

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));
        }
    }

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

您的ViewModel必须实现接口INotifyPropertyChanged并在任何绑定属性值更改时引发PropertyChanged事件,以便您的视图可以知道发生了更改。

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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM