Xamarin.Forms & C# 中的 MVVM:调用 OnPropertyChanged 时,PropertyChanged 事件处理程序始终为空

Xamarin.Forms & MVVM In C#: PropertyChanged Event Handler Is Always Null When OnPropertyChanged Called

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

以下是我的 MainPage 实现以及支持 ViewModel class、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));
        }
    }
}

当前实现执行以下操作:

'DataBoundDatePicker.UWP.exe' (CoreCLR: CoreCLR_UWP_Domain): Loaded 'c:\work\Xamarin\DataBoundDatePicker\DataBoundDatePicker\DataBoundDatePicker.UWP\bin\x86\Debug\AppX\Xamarin.Forms.Xaml.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. Entering MainPage.MainPage() - Constructor Entering SelectedDateViewModel.SelectedDateViewModel() - Constructor Inside SelectedDateViewModel.OnPropertyChanged() SelectedDate = Tuesday, July 4, 2017 PropertyChanged Is Null: Yes Leaving SelectedDateViewModel.SelectedDateViewModel() - Constructor Leaving MainPage.MainPage() - Constructor The thread 0x1630 has exited with code 0 (0x0). Inside SelectedDateViewModel.OnPropertyChanged() SelectedDate = Sunday, March 4, 2012 PropertyChanged Is Null: Yes

关于如何让文本 属性 将其文本 属性 绑定到 在 PropertyChanged 事件不是空引用的情况下使用 ViewModel 的日期 属性 将不胜感激。

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

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