【发布时间】:2017-10-30 11:25:18
【问题描述】:
我制作了一个简单的 MVVM 示例。我有两个用户控制页面的主窗口。主窗口有两个事件将视图更改为两个用户控件。
这是我的主窗口 XAML
<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:local="clr-namespace:MVVC_Binding"
xmlns:views="clr-namespace:MVVC_Binding.Views"
xmlns:viewModel="clr-namespace:MVVC_Binding.ViewModels"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" x:Class="MVVC_Binding.MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type viewModel:Page1ViewModel}">
<views:Page1 />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModel:Page2ViewModel}">
<views:Page2/>
</DataTemplate>
</Window.Resources>
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<TextBlock Text="Page1">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<i:InvokeCommandAction Command="{Binding NavCommand}" CommandParameter="page1"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
<TextBlock Text="Page2">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<i:InvokeCommandAction Command="{Binding NavCommand}" CommandParameter="page2"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</StackPanel>
<DockPanel Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top" Background="Gainsboro">
<Grid x:Name="container" Background="Gainsboro" VerticalAlignment="Top">
<ContentControl Content="{Binding CurrentViewModel}"/>
</Grid>
</DockPanel>
</Grid>
</Window>
我正在为我的视图模型使用 BindableBase 类。这是我的 BindableBase 类
namespace MVVC_Binding.Utilities
{
public class BindableBase : INotifyPropertyChanged
{
/// <summary>
/// Interface implementation
/// </summary>
public event PropertyChangedEventHandler PropertyChanged = delegate { };
protected virtual void SetProperty<T>(ref T member, T val, [CallerMemberName] string propertyName = null)
{
// Check for current set member and the new value
// If they are the same, do nothing
if (object.Equals(member, val)) return;
member = val;
// Invoke the property change event
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged(string propName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
在我的主视图模型中,只需简单的单击事件即可更改视图绑定
private BindableBase _CurrentViewModel;
public BindableBase CurrentViewModel
{
get { return _CurrentViewModel; }
set
{
SetProperty(ref _CurrentViewModel, value);
}
}
private void OnNav(string destination)
{
switch (destination)
{
case "page2":
CurrentViewModel = page2;
break;
default:
CurrentViewModel = page1;
break;
}
}
问题出在用户控件第2页,当它显示时,它旁边的事件并没有改变TextBlock绑定值,但是在视图模型构造函数事件期间文本可以改变。
这是我的第 2 页 XAML
<UserControl x:Class="MVVC_Binding.Views.Page2"
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:MVVC_Binding.Views"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<StackPanel>
<TextBlock Name="txtPage2" Text="{Binding Page2Text}"></TextBlock>
<TextBlock Name="btn" Text="Click Button">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<i:InvokeCommandAction Command="{Binding BtnCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</StackPanel>
</UserControl>
这里是 Page2ViewModel
namespace MVVC_Binding.ViewModels
{
public class Page2ViewModel : BindableBase
{
public MyICommand<string> BtnCommand { get; private set; }
public Page2ViewModel()
{
BtnCommand = new MyICommand<string>(OnBtnClick);
Page2Text = "Just a test";
}
private void OnBtnClick(string obj)
{
Page2Text = "Changing by button click";
}
private string _page2Text;
public string Page2Text
{
get { return _page2Text; }
set
{
_page2Text = value;
SetProperty(ref _page2Text, value);
}
}
}
}
你能看看我做错了什么吗?非常感谢
【问题讨论】:
-
@Aaron 的回答应该可以解决您的问题,但我想为您的
BindableBase添加一些有用的提示。如果您将SetProperty更改为返回bool,其中true表示该值已更新,而false如果未更新,则如果您需要在setter 中添加额外的逻辑,您可以进行一些非常有效的属性更改。我使用相同的模式,非常有帮助。 -
感谢@BradleyUffner,我更改了 Araon 提到的代码,但没有帮助。该值不会更新到视图。但是当我放置break时,当视图中的值发生变化时,我可以看到代码正确触发。并触发了 INotify 事件
-
PropertyChanged事件的设置和触发方式对我来说有点奇怪,但我不确定这是否真的是一个问题,或者只是与我习惯的不同。您之前是否使用过此BindableBase类并成功进行 2 向绑定,或者这是您第一次尝试使用它? -
这是我第一次使用它,我是从PluralSight课程中学习的,所以我尝试应用它。但奇怪的是,如果我从 Viewmodel 构造函数中更改文本,它将正确更新。它只会因命令事件而失败
-
那是因为构造函数在绑定之前运行,属性值在评估时已经到位,它只是拾取绑定时已经存在的内容,它不依赖在
PropertyChanged事件上通知它新值。尝试更改您的BindableBase使其看起来像 this 并让我知道它是否有任何不同。如果可行,我会为您输入答案。