单例中的INotifyPropertyChanged并绑定到WPF元素

时间:2013-04-18 16:07:54

标签: c# wpf mvvm binding

我再次尝试使用MVVM,目前我的代码遇到了两个问题。
首先让我解释一下代码结构:

我有一个这样的课程(当然简化):

public abstract class NavigationServiceBase : NotifyPropertyChangedBase, INavigationService
{
   private IView _currentView;
   public IView CurrentView
   {
       get { return _currentView; }
       protected set
       {
           _currentView = value;
           OnPropertyChanged("CurrentView");
       }
   }

   public virtual void DoSomethingFancy()
   { 
       CurrentView = ...; // here I expect it to fire OnPropertyChanged and notify my View
   }
}

继承自这个基类的单例:

public class NavigationService : NavigationServiceBase
{
    private static readonly INavigationService _instance = new NavigationService();
    public static INavigationService Instance { get { return _instance; } }

    ...
}

视图模型:

private INavigationService _navigationService;

public IView CurrentView { get { return _navigationService.CurrentView; } }
public ICommand NavigateCommand { get; private set; }

public MainWindowViewModel()
{
    _navigationService = NavigationService.Instance;
    NavigateCommand = new RelayCommand(param => Navigate(param));
}

private void Navigate(object requestedPage)
{
    _navigationService.Navigate((string)requestedPage);
    //OnPropertyChanged("CurrentView"); // this works , but...
}

现在问题:
1.)我在Visual Studio 2012 Express中编辑XAML。它似乎有效,但我收到一条警告:Unable to load one or more of the requested types. Retrieve the LoaderExceptions for more information.当我声明用于绑定ViewModel的资源时,它显示在该部分中。这是什么意思?如果我摆脱单身,消息就会消失。项目编译和运行都很好。

2。)似乎我的OnPropertyChanged(“CurrentView”)没有触发或其他东西,因为我必须从ViewModel本身手动调用此方法。如果我从基类或继承单例中尝试它,它就不起作用。 (绑定只是忽略新值)。如果我在处理命令时手动执行此操作,则可以正常工作。是的,这只是一个额外的代码行,但我想知道,有没有办法让它在没有“作弊”的情况下工作?

1 个答案:

答案 0 :(得分:2)

问题是您绑定到ViewModel中的属性:

public IView CurrentView { get { return _navigationService.CurrentView; } }

NatigationService正在提升PropertyChanged,但这种情况发生在_navigationService,而不是ViewModel本身,因此View永远不会看到该事件。

有两种常见的选择 -

您可以在导航服务上收听PropertyChanged事件,并在需要时处理本地事件:

_navigationService = NavigationService.Instance;
_navigationService.PropertyChanged += (o,e) => 
{
   // When navigation raises prop changed for this property, raise it too
   if (e.PropertyName == "CurrentView")
     OnPropertyChanged("CurrentView");
}; 
NavigateCommand = new RelayCommand(param => Navigate(param));

另一种方法是公开服务,并直接绑定到它:

public INavigationService Navigation { get { return _navigationService; } }

然后,在您的视图中,绑定到服务内部的内容而不是本地属性:

<ContentPresenter Content="{Binding Navigation.CurrentView}" />