Проблема привязки данных к универсальным приложениям Windows 8.1

Простая двусторонняя привязка данных к свойству модели не работает, чтобы воспроизвести проблему, я создал новый проект в Visual Studio 2013, т. Е. С шаблоном Blank App (Universal Apps) с.NET Framework 4.5.

Папки и файлы проекта

Модель

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

        public string FirstName { get; set; }

        public string LastName { get; set; }
    }
}

Модель базового вида

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

Интерфейс 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
    }
}

Модель основного вида

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

Просмотр главной страницы

<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>

Код главной страницы позади

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

Я попытался использовать Mode=TwoWay в TextBox, и он не работает, но когда я устанавливаю DataContext в xaml вместо кода, связывание данных работает даже без свойства Mode=TwoWay.

Я хочу установить DataContext в коде файла, как и в реальном проекте, где у меня возникла эта проблема, я использую библиотеки MVVM-light вместе с контейнером SimpleIoc, поэтому я хочу получить экземпляр модели представления из SimpleIoc и установить DataContext, потому что зависимости модели представления вводятся SimpleIoc, и код будет намного чище.

1 ответ

Решение

Проблема в том, что вы только уведомляете об изменении PersonModel Person, ViewModel необходимо уведомить об изменении свойства PersonModel,

Поскольку вы используете MVVM Light, измените модель на:

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; }
}
Другие вопросы по тегам