INotifyPropertyChanged 混乱
INotifyPropertyChange confusion
我正在将 VB.NET Winforms 项目转换为 C# WPF。
我有一个包含两个 WPF windows 和一个 ViewModel 作为引用项目的项目。
public class SheepViewModel : INotifyPropertyChanged
{
private string _CurrentEventName;
public string CurrentEventName
{
get { return _CurrentEventName; }
set
{
_CurrentEventName = value;
OnPropertyChanged("CurrentEventName");
}
}
static SheepViewModel _details;
public static SheepViewModel GetDetails()
{
if (_details == null)
_details = new SheepViewModel();
return _details;
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string prop)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(prop));
Console.WriteLine(prop + " has changed");
}
}
我显示东西的 window 看起来像这样。
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:SheepViewModel;assembly=SheepViewModel"
xmlns:ShaderEffectLibrary="clr-namespace:ShaderEffectLibrary;assembly=ShaderEffectLibrary" x:Class="Sheep_Score_3._1.ScoreScreen"
mc:Ignorable="d"
Title="ScoreScreen" Height="540" Width="920" WindowStartupLocation="CenterScreen">
<Window.DataContext>
<vm:SheepViewModel/>
</Window.DataContext>
<Viewbox x:Name="Stand1ViewBox" RenderTransformOrigin="0.5,0.5">
<Canvas x:Name="StandViewBox" Height="112.513" Margin="0,1100,2,0" VerticalAlignment="Bottom" RenderTransformOrigin="0.493,0.473" Background="#FF999999" Width="2268">
<TextBlock x:Name="CurrentEventName" Canvas.Left="270.9" TextWrapping="Wrap" Width="1104.815" FontFamily="Calibri" FontSize="29.333" FontStyle="Italic" Canvas.Top="-1.649" Text="{Binding Path=CurrentEventName}"/>
</Canvas>
</Viewbox>
</Window>
My MainWindow which is a control window looks like this
```xaml
<Window x:Class="Sheep_Score_3._1.MainWindow"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:SheepViewModel;assembly=SheepViewModel"
mc:Ignorable="d"
Title="MainWindow" Height="433.689" Width="941.194">
<Window.DataContext>
<vm:SheepViewModel/>
</Window.DataContext>
<Grid Margin="0,0,0,0">
<TextBox x:Name="CurrentEventName" Height="23" Margin="131.01,163.013,0,0" TextWrapping="Wrap" VerticalAlignment="Top" HorizontalAlignment="Left" Width="327.151" Text="{Binding CurrentEventName, Mode=TwoWay}"/>
</Grid>
</Window>
如果我在控件 window 文本框中键入内容,它会显示在文本块中 window 上,因此我的绑定正在工作,我可以看到 INotifyPropertyChanged.PropertyChanged
事件上调。一切都很好。
但是,如果我以编程方式更改 属性,我仍然可以看到引发的 INotifyPropertyChanged.PropertyChanged
事件,但文本框和文本块不会更新为新值。
SheepViewModel.SheepViewModel.GetDetails().CurrentEventName = "This is the new value";
我是不是漏掉了什么?
我真的很惊讶文本更新对你有用;它绝对不在我身边。原因如下:
您在两个 windows 中都有以下代码段:
<Window.DataContext>
<vm:SheepViewModel/>
</Window.DataContext>
这基本上是说:创建一个新的 SheepViewModel 实例并将其设置为 window 的数据上下文。由于您在两个 windows 中都有这个,每个 window 将有一个单独的 ViewModel 实例。由于 CurrentEventName
属性 是一个实例 属性,该值不会在实例之间共享,也不会正确更新。
当您尝试以编程方式更新值时,您调用 SheepViewModel.GetDetails()
。这会创建另一个实例,与控件使用的实例完全无关。因此,您看不到任何更新。
你想要的是以上所有使用一个视图模型实例。为此,您可以从后面的代码中设置 windows 的 DataContext。您可以在 windows:
中使用以下构造函数,而不是使用上面的 XAML 代码段
public DisplayWindow()
{
InitializeComponent();
this.DataContext = SheepViewModel.GetDetails();
}
这确保 windows 引用通过 GetDetails
方法检索的单例实例。
为了保证您的 windows 共享相同的视图模型,请删除 Steven 记录的片段并在您的 windows 的构造函数中调用以下代码:
DataContext = SheepViewModel.GetDetails();
我正在将 VB.NET Winforms 项目转换为 C# WPF。
我有一个包含两个 WPF windows 和一个 ViewModel 作为引用项目的项目。
public class SheepViewModel : INotifyPropertyChanged
{
private string _CurrentEventName;
public string CurrentEventName
{
get { return _CurrentEventName; }
set
{
_CurrentEventName = value;
OnPropertyChanged("CurrentEventName");
}
}
static SheepViewModel _details;
public static SheepViewModel GetDetails()
{
if (_details == null)
_details = new SheepViewModel();
return _details;
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string prop)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(prop));
Console.WriteLine(prop + " has changed");
}
}
我显示东西的 window 看起来像这样。
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:SheepViewModel;assembly=SheepViewModel"
xmlns:ShaderEffectLibrary="clr-namespace:ShaderEffectLibrary;assembly=ShaderEffectLibrary" x:Class="Sheep_Score_3._1.ScoreScreen"
mc:Ignorable="d"
Title="ScoreScreen" Height="540" Width="920" WindowStartupLocation="CenterScreen">
<Window.DataContext>
<vm:SheepViewModel/>
</Window.DataContext>
<Viewbox x:Name="Stand1ViewBox" RenderTransformOrigin="0.5,0.5">
<Canvas x:Name="StandViewBox" Height="112.513" Margin="0,1100,2,0" VerticalAlignment="Bottom" RenderTransformOrigin="0.493,0.473" Background="#FF999999" Width="2268">
<TextBlock x:Name="CurrentEventName" Canvas.Left="270.9" TextWrapping="Wrap" Width="1104.815" FontFamily="Calibri" FontSize="29.333" FontStyle="Italic" Canvas.Top="-1.649" Text="{Binding Path=CurrentEventName}"/>
</Canvas>
</Viewbox>
</Window>
My MainWindow which is a control window looks like this
```xaml
<Window x:Class="Sheep_Score_3._1.MainWindow"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:SheepViewModel;assembly=SheepViewModel"
mc:Ignorable="d"
Title="MainWindow" Height="433.689" Width="941.194">
<Window.DataContext>
<vm:SheepViewModel/>
</Window.DataContext>
<Grid Margin="0,0,0,0">
<TextBox x:Name="CurrentEventName" Height="23" Margin="131.01,163.013,0,0" TextWrapping="Wrap" VerticalAlignment="Top" HorizontalAlignment="Left" Width="327.151" Text="{Binding CurrentEventName, Mode=TwoWay}"/>
</Grid>
</Window>
如果我在控件 window 文本框中键入内容,它会显示在文本块中 window 上,因此我的绑定正在工作,我可以看到 INotifyPropertyChanged.PropertyChanged
事件上调。一切都很好。
但是,如果我以编程方式更改 属性,我仍然可以看到引发的 INotifyPropertyChanged.PropertyChanged
事件,但文本框和文本块不会更新为新值。
SheepViewModel.SheepViewModel.GetDetails().CurrentEventName = "This is the new value";
我是不是漏掉了什么?
我真的很惊讶文本更新对你有用;它绝对不在我身边。原因如下:
您在两个 windows 中都有以下代码段:
<Window.DataContext>
<vm:SheepViewModel/>
</Window.DataContext>
这基本上是说:创建一个新的 SheepViewModel 实例并将其设置为 window 的数据上下文。由于您在两个 windows 中都有这个,每个 window 将有一个单独的 ViewModel 实例。由于 CurrentEventName
属性 是一个实例 属性,该值不会在实例之间共享,也不会正确更新。
当您尝试以编程方式更新值时,您调用 SheepViewModel.GetDetails()
。这会创建另一个实例,与控件使用的实例完全无关。因此,您看不到任何更新。
你想要的是以上所有使用一个视图模型实例。为此,您可以从后面的代码中设置 windows 的 DataContext。您可以在 windows:
中使用以下构造函数,而不是使用上面的 XAML 代码段public DisplayWindow()
{
InitializeComponent();
this.DataContext = SheepViewModel.GetDetails();
}
这确保 windows 引用通过 GetDetails
方法检索的单例实例。
为了保证您的 windows 共享相同的视图模型,请删除 Steven 记录的片段并在您的 windows 的构造函数中调用以下代码:
DataContext = SheepViewModel.GetDetails();