从嵌套视图模型的属性更新标签

时间:2012-02-06 19:52:18

标签: wpf mvvm properties viewmodel

在我回答我的问题/问题之前,这是我的应用程序的基本结构:

在我的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级别缺少某些东西。我可以保持原样,但是它会进入子视图模型的结构,这不是我想要做的事情。

有人能指出我做错了吗?

3 个答案:

答案 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中。)