我一直在使用一种MVVM导航方法,我在其中为视图模型创建了一个datatempalte。 主窗口设置如下
<Window x:Class="VaultPrez.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ignore="http://www.ignore.com"
xmlns:v="clr-namespace:VaultPrez.Views"
xmlns:vm="clr-namespace:VaultPrez.ViewModel"
mc:Ignorable="d ignore"
Height="720"
Width="1280"
Title="MVVM Light Application"
DataContext="{Binding Main, Source={StaticResource Locator}}">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Skins/MainSkin.xaml" />
</ResourceDictionary.MergedDictionaries>
<DataTemplate DataType="{x:Type vm:MainMenuViewModel}">
<v:MainMenu />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:HeaderViewModel}">
<v:Header />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:MediaViewModel}">
<v:MediaViewer />
</DataTemplate>
</ResourceDictionary>
</Window.Resources>
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<ContentPresenter Grid.Row="0" Content="{Binding Header}" />
<ContentPresenter Grid.Row="1" Content="{Binding CurrentView}" />
</Grid>
名称空间v引用实际视图,vm是视图模型。 这是此视图的主视图模型
public class MainViewModel : ViewModelBase
{
private readonly DataAccessService dataService;
private ViewModelBase currentView;
private ViewModelBase header;
...
public Dictionary<string, ViewModelBase> Views { get; set; }
public ViewModelBase CurrentView
{
get { return currentView; }
set
{
if (currentView == null)
currentView = value;
else if (currentView != value)
{
ViewStates.Push(currentView);
currentView = value;
RaisePropertyChanged("CurrentView");
}
}
}
public ViewModelBase Header
{
get { return header; }
set
{
header = value;
RaisePropertyChanged("Header");
}
}
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel(IDataAccessService dataService)
{
this.dataService = dataService as DataAccessService;
Views = new Dictionary<string, ViewModelBase>();
ViewStates = new ObservableStack<ViewModelBase>();
ViewStates.CollectionChanged += ViewStates_CollectionChanged;
Views.Add("MainMenu", new MainMenuViewModel(dataService));
Views.Add("MediaViewer", new MediaViewModel(dataService));
CurrentView = Views["MainMenu"];
Header = new HeaderViewModel(dataService);
registerMessages();
}
private void registerMessages()
{
MessengerInstance.Register<BackMessage>(this, (message) =>
{
onBack();
});
MessengerInstance.Register<ChangeViewMessage>(this, (message) =>
{
CurrentView = Views[message.View];
});
MessengerInstance.Register<CancelBackMessage>(this, (message) =>
{
cancelBack = true;
waiting = false;
});
MessengerInstance.Register<SaveMediaMessage>(this, (message) =>
{
if (message.Media != null)
dataService.SaveMedia();
waiting = false;
});
}
void ViewStates_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (((ObservableStack<ViewModelBase>)sender).Count < 1)
MessengerInstance.Send<SetBackVisibilityMessage>(new SetBackVisibilityMessage() { Visibility = Visibility.Hidden });
else
MessengerInstance.Send<SetBackVisibilityMessage>(new SetBackVisibilityMessage() { Visibility = Visibility.Visible });
}
private void onBack()
{
//MessageBox.Show("Back");
if (currentView == Views["MediaViewer"])
{
waiting = true;
MessengerInstance.Send<AskSaveMediaMessage>(new AskSaveMediaMessage());
Task t = Task.Factory.StartNew(() =>
{
while (waiting)
if (!waiting) break;
});
t.Wait();
}
if(!cancelBack)
{
currentView = ViewStates.Pop();
RaisePropertyChanged("CurrentView");
}
cancelBack = false;
}
但相关的部分是视图模型存储在字典中,当主视图收到更改视图的消息时,它会将视图移动到指定的视图
MessengerInstance.Register<ChangeViewMessage>(this, (message) =>
{
CurrentView = Views[message.View];
});
理论上,当绑定CurrentView具有MainMenuViewModel的视图类型时,MainMenu显示等可以工作,但是当你更改它们时在其他视图上它没有第一次工作,所有绑定在视图上都是空的但是当你回到主菜单时,再试一次,它的一切都得到了正确的约束。
ViewModel也有数据,第一次尝试时没有任何内容。
如果它只是一个3或4个视图程序,我只是在加载过程中迭代每个视图,但我计划有大约20个视图,这可能会非常耗时。
我做了一些根本错误的事情吗?
编辑:这是ViewModelLocator.cs
public class ViewModelLocator
{
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (ViewModelBase.IsInDesignModeStatic)
{
}
else
{
SimpleIoc.Default.Register<IDataAccessService, DataAccessService>();
}
SimpleIoc.Default.Register<MainViewModel>();
SimpleIoc.Default.Register<MainMenuViewModel>();
SimpleIoc.Default.Register<HeaderViewModel>();
SimpleIoc.Default.Register<MediaViewModel>();
}
/// <summary>
/// Gets the Main property.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "This non-static member is needed for data binding purposes.")]
public MainViewModel Main
{
get { return ServiceLocator.Current.GetInstance<MainViewModel>(); }
}
public MainMenuViewModel Menu
{
get { return ServiceLocator.Current.GetInstance<MainMenuViewModel>(); }
}
public HeaderViewModel Header
{
get { return ServiceLocator.Current.GetInstance<HeaderViewModel>(); }
}
public MediaViewModel Media
{
get { return ServiceLocator.Current.GetInstance<MediaViewModel>(); }
}
/// <summary>
/// Cleans up all the resources.
/// </summary>
public static void Cleanup()
{
}
}
答案 0 :(得分:1)
就我所知,你的观点绝对没问题。我使用完全相同的机制,没有问题。我认为问题可能在于你的ViewModel:&#39; Views.Add(&#34; MainMenu&#34;,new MainMenuViewModel(dataService));&#39; 。新建ViewModel实例并不像您期望的那样工作。将(true)添加到SimpleIoc注册的末尾 - SimpleIoc.Default.Register(true);. ViewModels默认是延迟加载的单例。将true参数传递给SimpleIoc注册会关闭延迟加载。