PropertyChanged 仅在第一个事件上为 null
PropertyChanged is null only on the first event
我正在准备好使用 WPF 编写代码。所以我想出了一些基本的模拟代码来让自己继续下去。我拥有的是一个简单的 WPF 界面,其中有一个日期选择器、一些文本框和复选框。
我想用 INotifyPropertyChanged 界面做的是当我点击按钮时,我的文本框将只显示 "Hello Kevin"。为了测试它,我首先说我的字符串将以 "Initially" 开头,当我的方法 return 时,它将 return "Hello Kevin".
我还应该说明我做了一个模拟异步代码,它会调用服务器并在数据库中获取名称。这段代码工作得很好。问题是,当我第一次单击按钮时,PropretyChanged 首先为 null。但是,当我第二次点击它时,它会显示我想看到的消息。
这让我想知道该方法是否真正按照我的预期工作,所以我使用 Console.WriteLine 方法进行了一些基本测试,它只会显示我当前正在寻找的结果。
在下面,您可以找到我用于这个小螺柱软件的所有类:
public class ViewModelCommonBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
public class SimpleViewModel : ViewModelCommonBase
{
#region fields
private bool _isHealthCareEnabled=false;
private bool _isBenefits=false;
private bool _is401kEnabled=false;
private DateTime _birth;
#endregion
#region Properties
public int Age
{
get { return (int)((DateTime.Now - Birth).TotalDays)/365 ;}
}
public bool IsHealthCareEnabled
{
get { return _isHealthCareEnabled; }
set { _isHealthCareEnabled = value; }
}
public bool IsBenefitsEnabled
{
get { return _isBenefits; }
set
{
if (_isBenefits != value)
{
_isBenefits = value;
OnPropertyChanged("IsBenefitsEnabled");
}
}
}
public bool Is401kEnabled
{
get { return _is401kEnabled; }
set { _is401kEnabled = value; }
}
public DateTime Birth
{
get { return _birth; }
set
{
if (_birth != value)
{
_birth = value;
OnPropertyChanged("Birth");
OnPropertyChanged("Age");
}
}
}
#endregion
}
public class AsyncServerStud :ViewModelCommonBase
{
private string _nameOfPerson="Initial";
public string NameOfPerson
{
get { return _nameOfPerson; }
set
{
if (_nameOfPerson != value)
{
_nameOfPerson = value;
OnPropertyChanged("NameOfPerson");
}
}
}
public async void FindNameOfPerson()
{
var result = await FindNameOfPersonAsync("Kevin");
NameOfPerson = result;
Console.WriteLine(NameOfPerson);
}
private Task<string> FindNameOfPersonAsync(string name)
{
return Task.Factory.StartNew(() => SearchNameOfPerson(name));
}
private string SearchNameOfPerson(string name)
{
Thread.Sleep(6000);
return "Hello, " + name;
}
}
public class WPFViewModelPage
{
public SimpleViewModel SimpleViewModel { get; set; }
public AsyncServerStud MockServer { get; set; }
}
这是我用于所有数据绑定和用户界面的 XAML
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<!--<vm:SimpleViewModel x:Key="viewModel"/>-->
<vm:WPFViewModelPage x:Key="viewModel"/>
</Window.Resources>
<Grid Name="myGrid" DataContext="{Binding Source={StaticResource viewModel}}">
<CheckBox x:Name="chkBenefits"
Content="Has Benefits ?"
HorizontalAlignment="Left"
Margin="62,45,0,0"
VerticalAlignment="Top"
IsChecked="{Binding SimpleViewModel.IsBenefitsEnabled}"/>
<StackPanel IsEnabled="{Binding SimpleViewModel.IsBenefitsEnabled}">
<CheckBox Content="Health care"
HorizontalAlignment="Left"
Margin="85,86,0,0"
VerticalAlignment="Top"
IsEnabled="{Binding SimpleViewModel.IsBenefitsEnabled}"
IsChecked="{Binding SimpleViewModel.IsHealthCareEnabled}"/>
<DatePicker Name="mydatePicker" DisplayDate="{Binding SimpleViewModel.Birth}"/>
<TextBlock TextWrapping="Wrap" Text="{Binding SimpleViewModel.Age}"/>
<Button Content="Button" Click="Button_Click_1"/>
<TextBox Name="mySecondTextBox" Height="23" TextWrapping="Wrap" Text="{Binding MockServer.NameOfPerson }"/>
</StackPanel>
</Grid>
</Window>
当我删除 xaml 中的数据上下文引用并将其放在页面后面的代码中时(我知道 UI 中不应该有任何后面的代码,但请耐心等待)它工作。这对我来说是一些非常奇怪的东西。怎么可能一件事坏而另一件事好呢?
这里是后面的新代码
public WPFViewModelPage ViewModel { get; set; }
public MainWindow()
{
InitializeComponent();
ViewModel = new WPFViewModelPage()
{
SimpleViewModel = new SimpleViewModel(),
MockServer = new AsyncServerStud()
};
this.DataContext = ViewModel;
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
ViewModel.MockServer.FindNameOfPerson();
}
我对您的应用程序进行了以下更改,它对我有用。请尝试以下更改
将 DataContext
分配给 Window
而不是将其设置为 Grid
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:WpfApplication1"
Title="MainWindow"
Height="350"
Width="525">
<Window.DataContext>
<vm:WPFViewModelPage />
</Window.DataContext>
<Window.Resources>
<vm:WPFViewModelPage x:Key="viewModel" />
</Window.Resources>
<Grid Name="myGrid">
<CheckBox x:Name="chkBenefits"
Content="Has Benefits ?"
HorizontalAlignment="Left"
Margin="62,45,0,0"
VerticalAlignment="Top"
IsChecked="{Binding SimpleViewModel.IsBenefitsEnabled}" />
<StackPanel IsEnabled="{Binding SimpleViewModel.IsBenefitsEnabled}">
<CheckBox Content="Health care"
HorizontalAlignment="Left"
Margin="85,86,0,0"
VerticalAlignment="Top"
IsEnabled="{Binding SimpleViewModel.IsBenefitsEnabled}"
IsChecked="{Binding SimpleViewModel.IsHealthCareEnabled}" />
<DatePicker Name="mydatePicker"
DisplayDate="{Binding SimpleViewModel.Birth}" />
<TextBlock TextWrapping="Wrap"
Text="{Binding SimpleViewModel.Age}" />
<Button Content="Button"
Click="Button_Click" />
<TextBox Name="mySecondTextBox"
Height="23"
TextWrapping="Wrap"
Text="{Binding MockServer.NameOfPerson }" />
</StackPanel>
</Grid>
</Window>
像下面那样修改WPFViewModelPage
public class WPFViewModelPage
{
public SimpleViewModel SimpleViewModel { get; set; }
public AsyncServerStud MockServer { get; set; }
public WPFViewModelPage()
{
this.SimpleViewModel = new SimpleViewModel();
this.MockServer = new AsyncServerStud();
}
}
在您的 Button_Click
方法中添加以下代码
private void Button_Click(object sender, RoutedEventArgs e)
{
WPFViewModelPage dataContext = this.DataContext as WPFViewModelPage;
dataContext.MockServer.FindNameOfPerson();
}
我正在准备好使用 WPF 编写代码。所以我想出了一些基本的模拟代码来让自己继续下去。我拥有的是一个简单的 WPF 界面,其中有一个日期选择器、一些文本框和复选框。
我想用 INotifyPropertyChanged 界面做的是当我点击按钮时,我的文本框将只显示 "Hello Kevin"。为了测试它,我首先说我的字符串将以 "Initially" 开头,当我的方法 return 时,它将 return "Hello Kevin".
我还应该说明我做了一个模拟异步代码,它会调用服务器并在数据库中获取名称。这段代码工作得很好。问题是,当我第一次单击按钮时,PropretyChanged 首先为 null。但是,当我第二次点击它时,它会显示我想看到的消息。
这让我想知道该方法是否真正按照我的预期工作,所以我使用 Console.WriteLine 方法进行了一些基本测试,它只会显示我当前正在寻找的结果。
在下面,您可以找到我用于这个小螺柱软件的所有类:
public class ViewModelCommonBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
public class SimpleViewModel : ViewModelCommonBase
{
#region fields
private bool _isHealthCareEnabled=false;
private bool _isBenefits=false;
private bool _is401kEnabled=false;
private DateTime _birth;
#endregion
#region Properties
public int Age
{
get { return (int)((DateTime.Now - Birth).TotalDays)/365 ;}
}
public bool IsHealthCareEnabled
{
get { return _isHealthCareEnabled; }
set { _isHealthCareEnabled = value; }
}
public bool IsBenefitsEnabled
{
get { return _isBenefits; }
set
{
if (_isBenefits != value)
{
_isBenefits = value;
OnPropertyChanged("IsBenefitsEnabled");
}
}
}
public bool Is401kEnabled
{
get { return _is401kEnabled; }
set { _is401kEnabled = value; }
}
public DateTime Birth
{
get { return _birth; }
set
{
if (_birth != value)
{
_birth = value;
OnPropertyChanged("Birth");
OnPropertyChanged("Age");
}
}
}
#endregion
}
public class AsyncServerStud :ViewModelCommonBase
{
private string _nameOfPerson="Initial";
public string NameOfPerson
{
get { return _nameOfPerson; }
set
{
if (_nameOfPerson != value)
{
_nameOfPerson = value;
OnPropertyChanged("NameOfPerson");
}
}
}
public async void FindNameOfPerson()
{
var result = await FindNameOfPersonAsync("Kevin");
NameOfPerson = result;
Console.WriteLine(NameOfPerson);
}
private Task<string> FindNameOfPersonAsync(string name)
{
return Task.Factory.StartNew(() => SearchNameOfPerson(name));
}
private string SearchNameOfPerson(string name)
{
Thread.Sleep(6000);
return "Hello, " + name;
}
}
public class WPFViewModelPage
{
public SimpleViewModel SimpleViewModel { get; set; }
public AsyncServerStud MockServer { get; set; }
}
这是我用于所有数据绑定和用户界面的 XAML
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<!--<vm:SimpleViewModel x:Key="viewModel"/>-->
<vm:WPFViewModelPage x:Key="viewModel"/>
</Window.Resources>
<Grid Name="myGrid" DataContext="{Binding Source={StaticResource viewModel}}">
<CheckBox x:Name="chkBenefits"
Content="Has Benefits ?"
HorizontalAlignment="Left"
Margin="62,45,0,0"
VerticalAlignment="Top"
IsChecked="{Binding SimpleViewModel.IsBenefitsEnabled}"/>
<StackPanel IsEnabled="{Binding SimpleViewModel.IsBenefitsEnabled}">
<CheckBox Content="Health care"
HorizontalAlignment="Left"
Margin="85,86,0,0"
VerticalAlignment="Top"
IsEnabled="{Binding SimpleViewModel.IsBenefitsEnabled}"
IsChecked="{Binding SimpleViewModel.IsHealthCareEnabled}"/>
<DatePicker Name="mydatePicker" DisplayDate="{Binding SimpleViewModel.Birth}"/>
<TextBlock TextWrapping="Wrap" Text="{Binding SimpleViewModel.Age}"/>
<Button Content="Button" Click="Button_Click_1"/>
<TextBox Name="mySecondTextBox" Height="23" TextWrapping="Wrap" Text="{Binding MockServer.NameOfPerson }"/>
</StackPanel>
</Grid>
</Window>
当我删除 xaml 中的数据上下文引用并将其放在页面后面的代码中时(我知道 UI 中不应该有任何后面的代码,但请耐心等待)它工作。这对我来说是一些非常奇怪的东西。怎么可能一件事坏而另一件事好呢?
这里是后面的新代码
public WPFViewModelPage ViewModel { get; set; }
public MainWindow()
{
InitializeComponent();
ViewModel = new WPFViewModelPage()
{
SimpleViewModel = new SimpleViewModel(),
MockServer = new AsyncServerStud()
};
this.DataContext = ViewModel;
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
ViewModel.MockServer.FindNameOfPerson();
}
我对您的应用程序进行了以下更改,它对我有用。请尝试以下更改
将 DataContext
分配给 Window
而不是将其设置为 Grid
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:WpfApplication1"
Title="MainWindow"
Height="350"
Width="525">
<Window.DataContext>
<vm:WPFViewModelPage />
</Window.DataContext>
<Window.Resources>
<vm:WPFViewModelPage x:Key="viewModel" />
</Window.Resources>
<Grid Name="myGrid">
<CheckBox x:Name="chkBenefits"
Content="Has Benefits ?"
HorizontalAlignment="Left"
Margin="62,45,0,0"
VerticalAlignment="Top"
IsChecked="{Binding SimpleViewModel.IsBenefitsEnabled}" />
<StackPanel IsEnabled="{Binding SimpleViewModel.IsBenefitsEnabled}">
<CheckBox Content="Health care"
HorizontalAlignment="Left"
Margin="85,86,0,0"
VerticalAlignment="Top"
IsEnabled="{Binding SimpleViewModel.IsBenefitsEnabled}"
IsChecked="{Binding SimpleViewModel.IsHealthCareEnabled}" />
<DatePicker Name="mydatePicker"
DisplayDate="{Binding SimpleViewModel.Birth}" />
<TextBlock TextWrapping="Wrap"
Text="{Binding SimpleViewModel.Age}" />
<Button Content="Button"
Click="Button_Click" />
<TextBox Name="mySecondTextBox"
Height="23"
TextWrapping="Wrap"
Text="{Binding MockServer.NameOfPerson }" />
</StackPanel>
</Grid>
</Window>
像下面那样修改WPFViewModelPage
public class WPFViewModelPage
{
public SimpleViewModel SimpleViewModel { get; set; }
public AsyncServerStud MockServer { get; set; }
public WPFViewModelPage()
{
this.SimpleViewModel = new SimpleViewModel();
this.MockServer = new AsyncServerStud();
}
}
在您的 Button_Click
方法中添加以下代码
private void Button_Click(object sender, RoutedEventArgs e)
{
WPFViewModelPage dataContext = this.DataContext as WPFViewModelPage;
dataContext.MockServer.FindNameOfPerson();
}