0

La liaison de données bidirectionnelle simple à la propriété d'un modèle ne fonctionne pas. Pour reproduire le problème, j'ai créé un nouveau projet dans Visual Studio 2013 avec un modèle d'application vide (Universal Apps) avec .NET cadre 4,5Problème de liaison de données Windows Apps 8.1 universel

Project folders and files

Le modèle

namespace UWP.MVVM.Models 
{ 
    public class PersonModel 
    { 
     public int Id { get; set; } 

     public string FirstName { get; set; } 

     public string LastName { get; set; } 
    } 
} 

La vue de base du modèle

namespace UWP.MVVM.Core 
{ 
    using System.ComponentModel; 
    using System.Runtime.CompilerServices; 

    public class VMBase : INotifyPropertyChanged 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 

     public void NotifyPropertyChanged([CallerMemberName] string propertyName = "") 
     { 
      if (this.PropertyChanged != null) 
      { 
       this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
      } 
     } 
    } 
} 

L'interface INavigable

namespace UWP.MVVM.Core 
{ 
#if WINDOWS_PHONE_APP 
    using Windows.Phone.UI.Input; 
#endif 

    public interface INavigable 
    { 
     void Activate(object parameter); 

     void Deactivate(object parameter); 

#if WINDOWS_PHONE_APP 
     void BackButtonPressed(BackPressedEventArgs e); 
#endif 
    } 
} 

Le principal modèle vue

namespace UWP.MVVM.ViewModels 
{ 
    using UWP.MVVM.Core; 
    using UWP.MVVM.Models; 
#if WINDOWS_PHONE_APP 
    using Windows.Phone.UI.Input; 
#endif 

    public class MainViewModel : VMBase, INavigable 
    { 
     private PersonModel person; 

     public MainViewModel() 
     { 
      this.Person = new PersonModel(); 
     } 

     public PersonModel Person 
     { 
      get 
      { 
       return this.person; 
      } 
      set 
      { 
       if (value == this.person) 
       { 
        return; 
       } 

       this.person = value; 
       this.NotifyPropertyChanged(); 
      } 
     } 

     public void Activate(object parameter) 
     { 
      this.Person.FirstName = "Gerrard"; 
     } 

     public void Deactivate(object parameter) 
     { 
     } 

#if WINDOWS_PHONE_APP 
     public void BackButtonPressed(BackPressedEventArgs e) 
     { 
     } 
#endif 
    } 
} 

La vue principale de la page

<Page 
    x:Class="UWP.MVVM.MainPage" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="using:UWP.MVVM" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:vm="using:UWP.MVVM.ViewModels" 
    mc:Ignorable="d" 
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 
    <!--<Page.DataContext> 
     <vm:MainViewModel/> 
    </Page.DataContext>--> 

    <Grid Margin="24,24"> 
     <TextBox Header="First Name" 
       Text="{Binding Person.FirstName}"/> 
    </Grid> 
</Page> 

Le principal code de la page derrière

namespace UWP.MVVM 
{ 
    using UWP.MVVM.Core; 
#if WINDOWS_PHONE_APP 
    using Windows.Phone.UI.Input; 
#endif 
    using Windows.UI.Xaml.Controls; 
    using Windows.UI.Xaml.Navigation; 
    using UWP.MVVM.ViewModels; 

    /// <summary> 
    /// An empty page that can be used on its own or navigated to within a Frame. 
    /// </summary> 
    public sealed partial class MainPage : Page 
    { 
     public MainPage() 
     { 
      this.InitializeComponent(); 

      this.NavigationCacheMode = NavigationCacheMode.Required; 
      this.DataContext = new MainViewModel(); 
     } 

     /// <summary> 
     /// Invoked when this page is about to be displayed in a Frame. 
     /// </summary> 
     /// <param name="e">Event data that describes how this page was reached. 
     /// This parameter is typically used to configure the page.</param> 
     protected override void OnNavigatedTo(NavigationEventArgs e) 
     { 
      base.OnNavigatedTo(e); 
      var navigableViewModel = this.DataContext as INavigable; 
      if (navigableViewModel != null) 
      { 
       navigableViewModel.Activate(e.Parameter); 
      } 

#if WINDOWS_PHONE_APP 
      HardwareButtons.BackPressed += HardwareButtons_BackPressed; 
#endif 
     } 

     protected override void OnNavigatedFrom(NavigationEventArgs e) 
     { 
      base.OnNavigatedFrom(e); 
      var navigableViewModel = this.DataContext as INavigable; 
      if (navigableViewModel != null) 
      { 
       navigableViewModel.Deactivate(e.Parameter); 
      } 

#if WINDOWS_PHONE_APP 
      HardwareButtons.BackPressed -= HardwareButtons_BackPressed; 
#endif 
     } 

#if WINDOWS_PHONE_APP 
     private void HardwareButtons_BackPressed(object sender, BackPressedEventArgs e) 
     { 
      var navigableViewModel = this.DataContext as INavigable; 
      if (navigableViewModel != null) 
      { 
       navigableViewModel.BackButtonPressed(e); 
      } 
     } 
#endif 
    } 
} 

J'ai essayé d'utiliser Mode = TwoWay sur la TextBox et ça ne marche pas, mais quand je mets le DataContext dans xaml au lieu du code, alors la liaison de données fonctionne même sans la propriété Mode = TwoWay. Je veux définir DataContext dans le code derrière le fichier comme dans le projet réel où j'ai ce problème, j'utilise les bibliothèques MVVM-light avec son conteneur SimpleIoc, donc je veux obtenir l'instance du modèle de vue SimpleIoc et définissez DataContext car les dépendances du modèle de vue sont injectées par SimpleIoc et le code sera beaucoup plus propre.

+0

L'étiquette ** UWP ** devrait être utilisé que si cette question est sur le développement pour la plate-forme Windows Universal via Windows 10. Mais vous semble utiliser VS 2013 qui ne prend pas en charge le développement UWP. –

+0

D'accord, il devrait être Universal Windows Apps, je me suis trompé –

Répondre

1

Le problème est: vous notifiez uniquement le changement de PersonModel Person. Le ViewModel doit notifier la modification de la propriété de PersonModel.

Puisque vous utilisez MVVM Lumière, changer votre modèle:

public class PersonModel : ObservableObject 
{ 
    public int Id { get; set; } 

    string _FirstName = ""; 
    public string FirstName { 
     get { 
      return _FirstName; 
     } 
     set { 
      Set(ref _FirstName, value); 
     } 
    } 

    public string LastName { get; set; } 
} 
+0

Est-il correct d'implémenter INotifyPropertyChanged à la fois sur le ViewModel et le modèle ici dans ce contexte, ou devrais-je l'implémenter uniquement sur le modèle? –

+0

MVVM Light a ObservableObject pour être utilisé dans Model et BaseViewModel pour ViewModel. Les deux peuvent être utilisés pour notifier PropertyChanged. Si vous souhaitez conserver le modèle propre, vous pouvez également augmenter PropertyChanged pour la propriété 'Person' sur ViewModel:' NotifyPropertyChanged ("Person.FirstName"); ' Veuillez considérer accepter ma réponse si cela aide :) – thang2410199