在我回答我的问题/问题之前,这是我的应用程序的基本结构:
在我的MainWindow.xaml(本例中的主视图)中我有一个Label(我意识到我应该将其更改为TextBlock,但这是一个单独的问题):
<Label Name="StatusLabel" Content="{Binding Path=Status}"/>
它对应的ViewModel(MainWindowViewModel)包含另一个ViewModel(SiteListViewModel)和一个Status属性:
public class MainWindowViewModel : ViewModelBase
{
public SiteListViewModel SiteList { get; set; }
public String Status
{
get { return SiteList.Status; }
}
}
如您所见,MainWindowViewModel的Status属性返回SiteListViewModel实例的Status属性,其定义如下:
public class SiteListViewModel : ViewModelBase
{
private string status;
public String Status
{
get { return this.status; }
set
{
this.status = value;
base.OnPropertyChanged("Status");
}
}
}
SiteListViewModel的Status属性在异步处理期间在各个位置更新,以使用户了解正在进行的操作。这可以通过简单的赋值调用完成,例如:
Status = String.Format(Properties.Resources.SiteListViewModel_Status_LoadingJobs, count + 1, totalSites);
另一个重要的注意事项,MainWindowViewModel和SiteListViewModel都继承自实现INotifyPropertyChanged的ViewModelBase。
现在针对实际问题/问题:
标签不会更新。
但是,如果我将视图中的绑定更改为:
<Label Name="StatusLabel" Content="{Binding Path=SiteList.Status}"/>
工作正常。这似乎表明我在MainWindowViewModel级别缺少某些东西。我可以保持原样,但是它会进入子视图模型的结构,这不是我想要做的事情。
有人能指出我做错了吗?
答案 0 :(得分:3)
当然它没有更新,绑定系统会在拥有该属性的类型上侦听绑定属性的更改事件,根本不会触发任何通知。
您可以转发嵌套VM的通知:
public MainWindowViewModel
{
SiteList.PropertyChanged += (s,e)
=> if (e.PropertyName == "Status") OnPropertyChanged("Status");
}
OnPropertyChanged
是一种提升PropertyChanged
的方法;你的VM基类应该有类似的东西。
我建议删除该属性,但它是多余的,因为您可以通过SiteList
直接绑定(此属性也应该在其setter中触发更改通知)。此外,您需要从旧实例中分离处理程序,并在SiteList
更改时将其重新附加到新实例(也可以在setter中完成)。
答案 1 :(得分:0)
仅仅因为某些实现INotifyPropertyChanged
并不意味着它会自动知道属性何时发生变化。您需要在代码中引发PropertyChanged事件。
在您的示例中,可以通过注册SiteListViewMode.PropertyChanged
并在状态发生变化时针对PropertyChanged
提出Status
通知来完成此操作。
public class MainWindowViewModel : ViewModelBase
{
public SiteListViewModel SiteList { get; set; }
public String Status
{
get { return SiteList.Status; }
}
public MainWindowViewModel()
{
// Of course, verify property isn't null first.
// Also, it's probably best to attach this in the setter
// so you can unhook the event from old items too
SiteList.PropertyChanged += SiteList_PropertyChanged;
}
void SiteList_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Status")
RaisePropertyChanged("Status");
}
}
答案 2 :(得分:0)
因为MainWindow
的{{1}}是DataContext
。
MainWindowViewModel
将“继承”相同的Label
,因此DataContext
的{{1}} t也是Label
。这就是你必须DataContex
的原因。 (因为您没有在MainWindowViewModel
中提出SiteList.Status
但是在PropertyChanged
中。)