绑定不适用于第一次视图MvvmLight

时间:2015-04-14 23:11:26

标签: c# wpf mvvm-light

我一直在使用一种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()
    {
    }
}

1 个答案:

答案 0 :(得分:1)

就我所知,你的观点绝对没问题。我使用完全相同的机制,没有问题。我认为问题可能在于你的ViewModel:&#39; Views.Add(&#34; MainMenu&#34;,new MainMenuViewModel(dataService));&#39; 。新建ViewModel实例并不像您期望的那样工作。将(true)添加到SimpleIoc注册的末尾 - SimpleIoc.Default.Register(true);. ViewModels默认是延迟加载的单例。将true参数传递给SimpleIoc注册会关闭延迟加载。

相关问题