【问题标题】:Xamarin.Forms & MVVM In C#: PropertyChanged Event Handler Is Always Null When OnPropertyChanged CalledC# 中的 Xamarin.Forms 和 MVVM:调用 OnPropertyChanged 时,PropertyChanged 事件处理程序始终为空
【发布时间】:2017-12-12 10:50:46
【问题描述】:

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

除了支持 ViewModel 类 SelectedDateViewModel.cs 之外,以下是我的 MainPage 实现。

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 属性的日期字符串 选定日期视图模型。但是,对日期的任何后续更改 SelectedDatePicker 控件中的属性。

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

  • 尽管 SelectedDateViewModel.OnPropertyChanged() 被称为任何 在 DatePicker 中更改 Date 值的时间, SelectedDateViewModel 的 PropertyChanged 事件引用始终 null,即使在启动时(同样,当通过构造函数实例化时) 来电)。这与以下调试跟踪语句一起显示 当程序通过 Visual 在调试模式下运行时发出 工作室:

'DataBoundDatePicker.UWP.exe'(CoreCLR:CoreCLR_UWP_Domain):已加载 'c:\work\Xamarin\DataBoundDatePicker\DataBoundDatePicker\DataBoundDatePicker.UWP\bin\x86\Debug\AppX\Xamarin.Forms.Xaml.dll'。 跳过加载符号。模块经过优化和调试器选项 “只是我的代码”已启用。 进入 MainPage.MainPage() - 构造函数 进入 SelectedDateViewModel.SelectedDateViewModel() - 构造函数 在 SelectedDateViewModel.OnPropertyChanged() 内部 SelectedDate = 2017 年 7 月 4 日,星期二 PropertyChanged 为空:是 离开 SelectedDateViewModel.SelectedDateViewModel() - 构造函数 离开 MainPage.MainPage() - 构造函数 线程 0x1630 以代码 0 (0x0) 退出。 在 SelectedDateViewModel.OnPropertyChanged() 内部 SelectedDate = 2012 年 3 月 4 日,星期日 PropertyChanged 为空:是

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

您可以分享有关如何让 Text 属性将其 Text 属性绑定到 非常感谢使用 PropertyChanged 事件不是空引用的 ViewModel 的日期属性。

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

【问题讨论】:

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


    【解决方案1】:

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

    【讨论】:

    • 普拉提克;感谢您的答复。我按照您的建议更改了 OnPropertyChanged() 的实现,并且 PropertyChanged 仍然为空,即使调用了构造函数:Inside SelectedDateViewModel.OnPropertyChanged() SelectedDate = Thursday, August 9, 2018 PropertyChanged Is Null: Yes
    • 你使用 SelectedDateViewModel : INotifyPropertyChanged 吗?
    • 是的,Pratik,我重新编写(复制/粘贴)了您的 OnPropertyChanged() 实现,但 PropertyChanged 事件处理程序始终为空。很抱歉给您带来麻烦,但我还遗漏了什么吗?
    • 从受保护的虚拟 void OnPropertyChanged(string propertyName) 中删除虚拟并检查
    • 实际上,Patrik,我忽略了您最初的更正:缺少 SelectedDateViewModel 实现 INotfyProprttyChanged 接口的声明。你一开始就做对了。对于我的疏忽,我深表歉意,再次感谢。
    猜你喜欢
    • 1970-01-01
    • 2016-09-16
    • 2018-02-03
    • 2010-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-15
    相关资源
    最近更新 更多