【问题标题】:Universal Windows Apps 8.1 data binding issue通用 Windows Apps 8.1 数据绑定问题
【发布时间】:2016-06-04 07:04:40
【问题描述】:

与模型属性的简单双向数据绑定不起作用,为了重现该问题,我在 Visual Studio 2013 中创建了一个新项目,即使用带有 .NET 框架 4.5 的空白应用(通用应用)模板

Project folders and files

型号

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

我尝试在 TextBox 上使用 Mode=TwoWay,但它不起作用,但是当我在 xaml 中设置 DataContext 而不是后面的代码时,即使没有 Mode=TwoWay 属性,数据绑定也可以工作。

我想在文件后面的代码中设置 DataContext,就像在我遇到这个问题的实际项目中一样,我正在使用 MVVM-light 库及其 SimpleIoc 容器,所以我想从 SimpleIoc 获取视图模型实例并设置DataContext,因为视图模型依赖是由SimpleIoc注入的,代码会干净很多。

【问题讨论】:

  • 标签 UWP 只有在这个问题是关于通过 Windows 10 为通用 Windows 平台开发时才应该使用。但您似乎使用的是不支持的 VS 2013 UWP 开发。
  • 好吧,应该是通用 Windows 应用,我弄错了

标签: xaml mvvm win-universal-app mvvm-light windows-8.1-universal


【解决方案1】:

问题是:你只通知PersonModel Person的变化。 ViewModel需要通知PersonModelproperty的变化。

由于您使用的是 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; }
}

【讨论】:

  • 在这种情况下,可以在 ViewModel 和 Model 上都实现 INotifyPropertyChanged,还是应该只在 Model 上实现?
  • MVVM Light 具有用于模型的 ObservableObject 和用于 ViewModel 的 BaseViewModel。两者都可用于通知 PropertyChanged。如果您想保持模型干净,您也可以在 ViewModel 上为 Person 属性提高 PropertyChanged:NotifyPropertyChanged("Person.FirstName"); 如果有帮助,请考虑接受我的回答 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-30
  • 1970-01-01
  • 1970-01-01
  • 2011-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多