1

我再次尝试使用 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 本身手动调用此方法。如果我从基类或继承单例中尝试它,它不起作用。(绑定只是忽略新值)。如果我在传递命令时手动执行此操作,它会起作用。是的,这只是额外的一行代码,但我想知道,有没有办法让它在没有这样“作弊”的情况下工作?

4

1 回答 1

3

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

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

NatigationService是 raise 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}" />
于 2013-04-18T16:13:56.030 回答