c# - 即使更改了 INotifyProperty,WPF XAML 控件绑定也不会更新
问题描述
我在 DayView.xaml 中有一个 ContentControl,其内容绑定到 DayViewModel.cs 中的 CurrentSongViewModel 属性。CurrentSongViewModel 在 ContentControl 中是 DataTemplated 以根据视图模型(DefaultSongViewModel 或 EditSongViewModel)显示其各自的视图,并且两个 DataTemplates 都被确认可以工作。当我单击 DefaultSongView.xaml 上的“编辑”按钮时,EditSongCommand 将执行并将 CurrentSongViewModel 设置为新的 EditSongViewModel。CurrentSongViewModel 设置器调用 OnPropertyChanged(),但 ContentControl 内容没有更新!我在 OnPropertyChanged() 调用上设置了断点,它正在调用它。不知道为什么不更新。。。
DayView.xaml
<UserControl x:Class="Calandar.Views.DayView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Calandar.Views"
xmlns:viewmodels="clr-namespace:Calandar.ViewModels"
d:DataContext="{d:DesignInstance Type=viewmodels:DayViewModel}"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Background="LightSteelBlue">
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Text="Day" Grid.Row="0" FontSize="35" FontFamily="Yu Gothic UI Semibold" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="400"/>
<ColumnDefinition Width="400"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" >
<Border Style="{StaticResource PurpleBorder}">
<!-- The binding that isnt working -->
<ContentControl Content="{Binding CurrentSongViewModel}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type viewmodels:DefaultSongViewModel}">
<local:DefaultSongView/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodels:EditSongViewModel}">
<local:EditSongView/>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</Border>
</StackPanel>
</Grid>
</Grid>
</UserControl>
DefaultSongView.xaml
<UserControl x:Class="Calandar.Views.DefaultSongView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Calandar.Views"
xmlns:viewmodels="clr-namespace:Calandar.ViewModels"
d:DataContext="{d:DesignInstance Type=viewmodels:DayViewModel}"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.DataContext>
<viewmodels:DayViewModel/>
</Grid.DataContext>
<StackPanel>
<DockPanel >
<Button Content="Edit" Command="{Binding EditSongCommand}"
Style="{StaticResource CollectionModifierButton}" DockPanel.Dock="Right"/>
<TextBlock Text="Songs" Style="{StaticResource BoxTitleText}" DockPanel.Dock="Top"/>
</DockPanel>
<ListBox ItemsSource="{Binding SongList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=.}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Grid>
</UserControl>
DayViewModel.cs
public class DayViewModel : ViewModelBase
{
// content view models
private ViewModelBase _currentSongViewModel;
public ViewModelBase CurrentSongViewModel
{
get { return _currentSongViewModel; }
set
{
_currentSongViewModel = value;
OnPropertyChanged(nameof(CurrentSongViewModel));
}
}
// Song list
public ObservableCollection<string> SongList { get; set; }
// Commands
public ICommand EditSongCommand => new EditSongsCommand(this);
// Constructor
public DayViewModel()
{
_currentSongViewModel = new DefaultSongViewModel();
SongList = new ObservableCollection<string>();
foreach (string line in File.ReadLines(@"C:\Users\person\source\repos\Calandar\DataFiles\Songs.txt"))
{
SongList.Add(line);
}
}
}
EditSongCommand.cs
public class EditSongsCommand : CommandBase
{
DayViewModel _vm;
public override bool CanExecute(object parameter) => true;
public override void Execute(object parameter)
{
_vm.CurrentSongViewModel = new EditSongViewModel();
}
public EditSongsCommand(DayViewModel vm)
{
_vm = vm;
}
}
ViewModelBase.cs
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string PropertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
}
解决方案
以下标记将 设置DataContext
为 的另一个实例DayViewModel
:
<Grid.DataContext>
<viewmodels:DayViewModel/>
</Grid.DataContext>
您应该使用以下命令将其从DefaultSongView.xaml
父视图模型的命令中删除并绑定到RelativeSource
:
<Button
Content="Edit"
Command="{Binding DataContext.EditSongCommand, RelativeSource={RelativeSource AncestorType=ContentControl}}"
推荐阅读
- node.js - 尝试将用于 web 的 Node.js React 应用程序部署到 Heroku 或 Github Pages,它可以在本地工作,而不能在 Heroku 上工作。为什么?
- reactjs - 我如何在 reactjs 中实现这一点而不替换新触发器中的第一个触发器崩溃
- bash - BASH:子命令扩展中不可避免的分词?
- mysql - 是否有用于存储原材料、中间产品和最终产品的 MYSQL 表模式?
- docker - 为什么所有 MariaDB 容器之间共享数据库存储?
- model-view-controller - 存储在 mvc 的 app_data 文件夹中的文件的 URL
- .net - 多绑定表达式总是在它的多转换器中显示 DependencyProperty.UnsetValue
- c++ - 如何在 for 循环中的特定时间打印额外的值
- python - 搜索和查找从另一个数据帧中的一个数据帧搜索值,并根据熊猫中的查找值填充新列
- amazon-web-services - 关于到 AWS Lambda 的 KInesis Firehose 数据流