每次使用MVVMLight WPF导航到页面时如何调用函数

时间:2018-10-24 13:40:03

标签: c# wpf mvvm-light

这是我的情况。我有一个页面可以从数据库中加载碱基列表。如果导航到页面,则调用构造函数,并调用我的LoadBases()函数。太好了,正是我所需要的。

问题:

如果我离开该页面并从另一个页面向数据库中添加更多基础,然后又向后导航,则不会调用构造函数,因此新的基础不会加载到我的基础列表中。

我尝试过的事情:

在MVVMLight中查看模型定位器

public class ViewModelLocator
{
    static ViewModelLocator()
    {
        SetupNavigation();
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
        SimpleIoc.Default.Register<BomConfiguratorContext>();

        if (ViewModelBase.IsInDesignModeStatic)
        {
            SimpleIoc.Default.Register<IUnitOfWork, UnitOfWork>();
        }
        else
        {
            SimpleIoc.Default.Register<IUnitOfWork, UnitOfWork>();
        }

        //   SimpleIoc.Default.Register<MainViewModel>();
        SimpleIoc.Default.Register<LoginViewModel>();
        SimpleIoc.Default.Register<UserNavigationViewModel>();
        SimpleIoc.Default.Register<AddNewBasesViewModel>();
        SimpleIoc.Default.Register<AddNewBillOfMaterialsViewModel>();
        SimpleIoc.Default.Register<AddNewOptionsViewModel>();
        SimpleIoc.Default.Register<AddNewRulesViewModel>();
        SimpleIoc.Default.Register<GenerateBillOfMaterialsViewModel>();

    }

    /// <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 LoginViewModel LoginViewModel
    {
        get{ return ServiceLocator.Current.GetInstance<LoginViewModel>(); }
    }
    public UserNavigationViewModel ManageRulesViewModel
    {
        get { return ServiceLocator.Current.GetInstance<UserNavigationViewModel>(); }
    }
    public AddNewBasesViewModel AddNewBasesViewModel
    {
        get { return ServiceLocator.Current.GetInstance<AddNewBasesViewModel>(); }
    }
    public AddNewBillOfMaterialsViewModel AddNewBillOfMaterialsViewModel
    {
        get { return ServiceLocator.Current.GetInstance<AddNewBillOfMaterialsViewModel>(); }
    }
    public AddNewOptionsViewModel AddNewOptionsViewModel
    {
        get { return ServiceLocator.Current.GetInstance<AddNewOptionsViewModel>(); }
    }
    public AddNewRulesViewModel AddNewRulesViewModel
    {
        get
        {
            SimpleIoc.Default.Unregister<AddNewRulesViewModel>();
            SimpleIoc.Default.Register<AddNewRulesViewModel>();
            return ServiceLocator.Current.GetInstance<AddNewRulesViewModel>();
        }
    }
    public GenerateBillOfMaterialsViewModel GenerateBillOfMaterialsViewModel
    {
        get{return ServiceLocator.Current.GetInstance<GenerateBillOfMaterialsViewModel>();}
    }

    /// <summary>
    /// Cleans up all the resources.
    /// </summary>
    public static void Cleanup()
    {
    }

    private static void SetupNavigation()
    {
        SimpleIoc.Default.Unregister<INavigationService>();
        var navigationService = new FrameNavigationService();
        navigationService.Configure("LoginView", new Uri("/Views/LoginView.xaml", UriKind.Relative));
        navigationService.Configure("UserNavigationView", new Uri("/Views/UserNavigationView.xaml", UriKind.Relative));
        navigationService.Configure("AddNewBasesView", new Uri("/Views/Bases/AddNewBasesView.xaml", UriKind.Relative));
        navigationService.Configure("AddNewBillOfMaterialsView", new Uri("/Views/BillOfMaterials/AddNewBillOfMaterialsView.xaml", UriKind.Relative));
        navigationService.Configure("AddNewOptionsView", new Uri("/Views/Options/AddNewOptionsView.xaml", UriKind.Relative));
        navigationService.Configure("AddNewRulesViewStep1", new Uri("/Views/Rules/AddNewRules/AddNewRulesStep1.xaml", UriKind.Relative));
        navigationService.Configure("AddNewRulesViewStep2", new Uri("/Views/Rules/AddNewRules/AddNewRulesStep2.xaml", UriKind.Relative));
        navigationService.Configure("AddNewRulesViewStep3", new Uri("/Views/Rules/AddNewRules/AddNewRulesStep3.xaml", UriKind.Relative));
        navigationService.Configure("AddNewRulesViewStep4", new Uri("/Views/Rules/AddNewRules/AddNewRulesStep4.xaml", UriKind.Relative));
        navigationService.Configure("AddNewRulesViewStep5", new Uri("/Views/Rules/AddNewRules/AddNewRulesStep5.xaml", UriKind.Relative));
        navigationService.Configure("AddNewRulesViewStep6", new Uri("/Views/Rules/AddNewRules/AddNewRulesStep6.xaml", UriKind.Relative));
        navigationService.Configure("AddNewRulesViewStep7", new Uri("/Views/Rules/AddNewRules/AddNewRulesStep7.xaml", UriKind.Relative));
        navigationService.Configure("GenerateBillOfMaterialsView", new Uri("/Views/BillOfMaterials/GenerateBillOfMaterialsView.xaml", UriKind.Relative));
        SimpleIoc.Default.Register<INavigationService>(() => navigationService);
    }
}

查看采用INavigationService的模型

仅是我如何注入导航服务并将其用于导航页面的示例。

public LoginViewModel(IUnitOfWork unitOfWork, INavigationService navService)
    {
        _UnitOfWork = unitOfWork;
        _NavigationService = navService;
        LoginCommand = new RelayCommand<IHavePassword>((IHavePassword parameter) => LoginAsync(parameter));
    }

导航到页面

 private async void LoginAsync(IHavePassword parameter)
    {
       if( await Task<bool>.Run(() => Login(parameter)))
            _NavigationService.NavigateTo("UserNavigationView");

    }

我正在导航到的页面

这只是我如何在页面中使用数据上下文的一个示例。

<local:BasePage x:Class="YAI.BomConfigurator.Desktop.Views.UserNavigationView"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
  xmlns:local="clr-namespace:YAI.BomConfigurator.Desktop"
  mc:Ignorable="d" 
  d:DesignHeight="600" d:DesignWidth="800"
  Title="UserNavigationView"
  DataContext="{Binding ManageRulesViewModel, Source={StaticResource Locator}}">

<Border>
    <Grid>
        <ScrollViewer>
            <StackPanel
                VerticalAlignment="Center"
                HorizontalAlignment="Center"
                TextBlock.TextAlignment="Center">
                <Border Background="{StaticResource BackgroundLightBrush}"
                        CornerRadius="10"
                        Padding="15 50 15 15"
                        Width="600"
                        Margin="50 50 50 0">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Grid.ColumnSpan="2" Text="I Would Like To..." 
                                   FontSize="{StaticResource FontSizeLarge}"
                                   FontFamily="{StaticResource LatoRegular}"
                                   Foreground="{StaticResource MediumBlueBrush}"
                                   Margin="0 0 0 15"/>
                        <StackPanel Grid.Column="0" Margin="0 0 25 0">

                            <Button Content="Generate BOMs"
                                Margin="0 50 0 20"
                                Command="{Binding GenerateBillOfMaterialsCommand}"/>
                            <Button Content="Check Rules"
                                    Margin="0 25 0 20"
                                    Command="{Binding CheckRulesCommand}"/>
                            <Button Content="Add New Options"
                                    Margin="0 25 0 20"
                                    Command="{Binding AddNewOptionsCommand}"/>
                        </StackPanel>
                        <StackPanel Grid.Column="1">
                            <Button Content="Add New BOMs"
                                    Margin="0 50 0 20"
                                    Command="{Binding AddNewBillOfMaterialsCommand}" />
                            <Button Content="Add New Rules"
                                    Margin="0 25 0 20"
                                    Command="{Binding AddNewRulesCommand}"/>
                            <Button Content="Add New Bases"
                                    Margin="0 25 0 20"
                                    Command="{Binding AddNewBasesCommand}"/>
                        </StackPanel>

                    </Grid>
                </Border>
            </StackPanel>
        </ScrollViewer>
    </Grid>
</Border>

此解决方案的问题在于,在每次调用视图模型时注销和重新注册视图模型时,当我浏览所有都使用datacontext AddNewRulesViewModel的视图时,它将从字面上清除所有变量并为每个对象调用构造函数页面(其中有7个使用相同的视图模型)。

所以我要寻找的是仅当我导航到特定页面时才调用LoadBases()函数的方法。谁能给我一些有关如何解决此问题的建议?

1 个答案:

答案 0 :(得分:1)

我最终解决此问题的方法是在页面加载事件上使用事件触发器。这是我所做的小事。

以xaml触发

<i:Interaction.Triggers>
    <i:EventTrigger EventName="Loaded">
        <i:InvokeCommandAction Command="{Binding LoadAllDataCommand}" />
    </i:EventTrigger>
</i:Interaction.Triggers>

查看模型LoadAllDataCommand

LoadAllDataCommand = new RelayCommand(async () => await LoadAllDataAsync());

查看模型命令操作

 private async Task LoadAllDataAsync()
    {
        AllBases.Clear();
        try
        {
            using (var UOW = _UnitOfWorkFactory.Create())
            {
                foreach (Base ba in await Task.Run(() => _BaseRepository.GetAll()))
                {
                    AllBases.Add(ba);
                }
            }
        }
        catch (Exception)
        {
            await Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => {
                Messenger.Default.Send(new ToastErrorMessage { Message = "Error: There was a problem with loading the data" });
            }));
        }     
    }

因此,每次加载页面时,都会使用所有新添加的库从数据库中重新加载我的数据。