Xamarin.Forms& C#中的MVVM:当OnPropertyChanged调用

时间:2017-07-08 04:52:57

标签: c# mvvm data-binding xamarin.forms propertychanged

我在Visual Studio 2017的C#中使用Xamarin.Forms编写了一个简单的应用程序,并且数据绑定有问题,需要更新Label子控件的内容以显示DatePicker子控件中的选定日期值相同的ContentPage。虽然所有项目元素都可以编译,构建和部署而没有任何错误,并且每当我更改DatePicker中选择的日期时,每次调用ViewModel中的OnPropertyChanged方法时,PropertyChanged事件处理程序始终是一个空对象引用。调用OnPropertyChanged方法,反过来,不会按预期使用新选择的日期值更新Label的Text属性的内容。

以下是我的MainPage实现以及支持ViewModel类,SelectedDateViewModel.cs。

C#[MainPage.xaml.cs]

using System;
using Xamarin.Forms;

namespace DataBoundDatePicker
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();

            BindingContext = new SelectedDateViewModel();
        }
    }
}

XAML [MainPage.xaml]

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataBoundDatePicker"
             x:Class="DataBoundDatePicker.MainPage">
    <StackLayout Padding="20" VerticalOptions="Center" HorizontalOptions="Center">
        <Label Text="Data Bound DatePicker" FontAttributes="Bold" HorizontalOptions="Center" />
        <Label Text="Select a Date:" />
        <DatePicker x:Name="SelectedDatePicker" Date="{Binding SelectedDate}"/>
        <StackLayout Orientation="Horizontal">
            <Label Text="Formatted Date:" />
            <Label x:Name="FormattedDateLabel" Text="{Binding SelectedDate, StringFormat='{0:dddd, MMMM d, yyyy}'}" />
        </StackLayout>
    </StackLayout>
</ContentPage>

C#[SelectedDateViewModel.cs]

using System;
using System.ComponentModel;
using System.Diagnostics;

namespace DataBoundDatePicker
{
    public class SelectedDateViewModel
    {
        private readonly string FullDateFormat = "dddd, MMMM d, yyyy";

        private DateTime selectedDate;

        public event PropertyChangedEventHandler PropertyChanged;

        public SelectedDateViewModel()
        {
            Debug.WriteLine("Entering SelectedDateViewModel.SelectedDateViewModel() - Constructor");

            SelectedDate = DateTime.Now;

            Debug.WriteLine("Leaving SelectedDateViewModel.SelectedDateViewModel() - Constructor");
        }

        public DateTime SelectedDate
        {
            get
            {
                return selectedDate;
            }

            set
            {
                if (selectedDate != value)
                {
                    selectedDate = value;
                    OnPropertyChanged("SelectedDate");
                }
            }
        }

        protected virtual void OnPropertyChanged(string propertyName)
        {
            Debug.WriteLine("Inside SelectedDateViewModel.OnPropertyChanged()");

            Debug.WriteLine($"SelectedDate = {selectedDate.ToString(FullDateFormat)}");

            var trace =
            $"PropertyChanged Is Null: {(PropertyChanged == null ? "Yes" : "No")}";
            Debug.WriteLine(trace);

            var propertyChangedCallback = PropertyChanged;
            propertyChangedCallback?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

当前的实现执行以下操作:

  • 启动时,FormattedDateLabel显示正确的格式 日期字符串基于的SelectedDate DateTime属性 SelectedDateViewModel。但是,日期的任何后续更改 在SelectedDatePicker控件中的属性。

  • 没有失败,每次都会更改日期值 SelectedDatePicker控件, 始终调用SelectedDateViewModel.OnPropertyChanged()方法, 甚至在启动时通过MainPage实例化和 SelectedDateViewModel对象实例(例如,构造函数调用)。

  • 虽然调用了SelectedDateViewModel.OnPropertyChanged() 在DatePicker中更改Date值的时间, SelectedDateViewModel的PropertyChanged事件引用始终是 null,即使在启动时(再次,通过构造函数实例化时) 调用)。这与以下Debug跟踪语句一起显示 当程序通过Visual在Debug模式下运行时发出 工作室:

  

'DataBoundDatePicker.UWP.exe'(CoreCLR:CoreCLR_UWP_Domain):已加载   'C:\工作\ Xamarin \ DataBoundDatePicker \ DataBoundDatePicker \ DataBoundDatePicker.UWP \ BIN \ 86 \调试\ AppX中\ Xamarin.Forms.Xaml.dll'。   跳过加载符号。模块已优化并具有调试器选项   'Just My Code'已启用。       输入MainPage.MainPage() - 构造函数       输入SelectedDateViewModel.SelectedDateViewModel() - 构造函数       内部SelectedDateViewModel.OnPropertyChanged()       SelectedDate = 2017年7月4日星期二       PropertyChanged Null:是的       离开SelectedDateViewModel.SelectedDateViewModel() - 构造函数       离开MainPage.MainPage() - 构造函数       线程0x1630已退出,代码为0(0x0)。       内部SelectedDateViewModel.OnPropertyChanged()       SelectedDate = 2012年3月4日星期日       PropertyChanged Is Null:是的

  • 无论部署和调试如何,代码都表现出相同的行为 UWP或Android版本的应用程序。

您可以分享有关如何让Text属性将其Text属性绑定到的所有帮助或见解和解释  使用ViewModel的Date属性,其中PropertyChanged事件不是空引用,将非常感激。

提前感谢您的时间和帮助。

1 个答案:

答案 0 :(得分:3)

使用INotifyPropertyChanged接口。像这样。

public class SelectedDateViewModel : INotifyPropertyChanged
    {
        private readonly string FullDateFormat = "dddd, MMMM d, yyyy";

        private DateTime selectedDate;

        public event PropertyChangedEventHandler PropertyChanged;

        public SelectedDateViewModel()
        {
            Debug.WriteLine("Entering SelectedDateViewModel.SelectedDateViewModel() - Constructor");

            SelectedDate = DateTime.Now;

            Debug.WriteLine("Leaving SelectedDateViewModel.SelectedDateViewModel() - Constructor");
        }

        public DateTime SelectedDate
        {
            get
            {
                return selectedDate;
            }

            set
            {
                if (selectedDate != value)
                {
                    selectedDate = value;
                    OnPropertyChanged("SelectedDate");
                }
            }
        }

        protected virtual void OnPropertyChanged(string propertyName)
        {
             if (PropertyChanged != null)
             {
                  PropertyChanged(this,
                         new PropertyChangedEventArgs(propertyName));
             }
        }
    }