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