2017-04-18 56 views
0

我是相对较新的棱镜6,并已看着其他stackoverflow帖子试图获得我的问题的答案。我有一个视图模块构造函数,每次导航到页面时都会执行。WPF棱镜6查看模型创建不止一次

在引导文件,ConfigureContainer功能,我有以下声明:

base.ConfigureContainer(); 

//Container.RegisterInstance<JobList>(new JobList()); 
Container.RegisterTypeForNavigation<JobList>("JobList"); 

使用Container.RegisterInstance功能招贤纳才,似乎没有什么区别。

的作业表视图的顶部看起来是这样的:

<UserControl x:Class="JobListModule.Views.JobList" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core" 
    xmlns:prism="http://prismlibrary.com/" 
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
    prism:ViewModelLocator.AutoWireViewModel="True" 
    Width="1090" Height="900" 
> 
<i:Interaction.Triggers> 
    <prism:InteractionRequestTrigger SourceObject="{Binding ConfirmationRequest, Mode=OneWay}"> 
     <prism:PopupWindowAction IsModal="True" CenterOverAssociatedObject="True"/> 
    </prism:InteractionRequestTrigger> 
</i:Interaction.Triggers> 
<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="70*"/> 
     <RowDefinition Height="830*"/> 
    </Grid.RowDefinitions> 
    <Grid Row="0" OpacityMask="#FFEEEBEB" > 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="83*"/> 
      <ColumnDefinition Width="37*"/> 
     </Grid.ColumnDefinitions> 
     <Label x:Name="JobListLabel" Grid.Column="0" Content="{x:Static p:Resources.JobListBuildListLabelText}" HorizontalAlignment="Center" VerticalAlignment="Center" Width="613" FontSize="48" Margin="67,-2,74,2" Height="70" RenderTransformOrigin="1.695,0.222" FontWeight="Bold" Padding="0" Grid.IsSharedSizeScope="True" VerticalContentAlignment="Center" HorizontalContentAlignment="Center"/> 
     <Button x:Name="AddJobFileBtn" Command="{Binding AddJobBtnClickedCommand}" Grid.Column="1" Content="{x:Static p:Resources.JobListAddBuildFileBtnText}" HorizontalAlignment="Center" Margin="56,10,64,11" VerticalAlignment="Center" Width="216" Height="49" RenderTransformOrigin="0.203,-0.173" FontSize="32" FontWeight="Bold" Padding="0"> 
      <Button.Background> 
       <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> 
        <GradientStop Color="#FFBEC9CF"/> 
        <GradientStop Color="#FF5EB4C7" Offset="0.936"/> 
        <GradientStop Color="#FFC9E9F0" Offset="0.319"/> 
       </LinearGradientBrush> 
      </Button.Background> 
     </Button> 
    </Grid> 
    <ListBox x:Name="BuildList" Grid.Row="1" Margin="0,0,0,0" ItemsSource="{Binding Path=JobFileInfoList}" SelectedIndex="{Binding Path=JobListSelectedItemIndex, Mode=TwoWay}"> 
     <ListBox.ItemTemplate> 
      <DataTemplate > 
       <Grid> 
        <Grid.RowDefinitions> 
         <RowDefinition Height="114*"/> 
        </Grid.RowDefinitions> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition Width="750"/> 
         <ColumnDefinition Width="100*"/> 
         <ColumnDefinition Width="200*"/> 
        </Grid.ColumnDefinitions> 
        <Label x:Name="JobFileNameLabel" Grid.Column="0" Content="{Binding JobFileName}" HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="24" FontWeight="Bold" Padding="0"/> 
        <dx:SimpleButton Command="{Binding DataContext.LoadJobBtnClickedCommand,RelativeSource={RelativeSource AncestorType=ListBox}}" CommandParameter="{Binding JobFileName}" Grid.Column="1" Content="{x:Static p:Resources.JobListPrintBtnLabelText}" HorizontalAlignment="Center" Margin="25,19,23,25" VerticalAlignment="Center" Width="120" Height="60" RenderTransformOrigin="0.203,-0.173" FontSize="32" FontWeight="Bold" Padding="0"/> 
        <dx:SimpleButton Command="{Binding DataContext.TrashCanBtnClickedCommand,RelativeSource={RelativeSource AncestorType=ListBox}}" CommandParameter="{Binding JobFileName}" Grid.Column="2" Margin="0" BorderThickness="0" HorizontalAlignment="Center" Width="86" Height="86" VerticalAlignment="Center" Padding="0" Background="{x:Null}"> 
         <Image Source="..\ButtonImages\TrashCan-64.png" /> 
        </dx:SimpleButton> 
       </Grid> 
      </DataTemplate> 
     </ListBox.ItemTemplate> 
    </ListBox> 
</Grid> 
</UserControl> 

和JobList.xaml.cs文件包含:

public partial class JobList 
{ 
    public JobList() 
    { 
     InitializeComponent(); 
    } 
} 

的作业表视图模型如下:

using Common.GatedEvents; 
using CommonApp; 
using Prism.Commands; 
using Prism.Events; 
using Prism.Interactivity.InteractionRequest; 
using Prism.Mvvm; 
using Prism.Regions; 
using System; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.IO; 
using System.Linq; 
using System.Windows; 
using System.Windows.Input; 
using VulcanGUI.Services; 
using VulcanGUI.Logging; 
using VulcanGUI.DialogService; 
using VulcanGUI.DialogService.ViewModels; 

namespace VulcanGUI.JobListModule.ViewModels 
{ 
public class JobListViewModel : BindableBase, IDescribe, IInteractionRequestAware, INavigationAware 
{ 
    private readonly IRegionManager _regionManager; 
    private readonly log4net.ILog _logger; 
    protected readonly IEventAggregator EventAggregator; 

    // Delete Job Queue AMX File Confirmation 
    public InteractionRequest<IConfirmation> ConfirmationRequest { get; private set; } 
    public InteractionRequest<INotification> ErrorNotification { get; private set; } 

    private bool _deleteJobConfirmationRequestResult; 
    private bool _printJobConfirmationRequestResult; 
    public DelegateCommand RaiseDeleteJobConfirmationCommand { get; private set; } 
    public DelegateCommand RaiseLoadJobConfirmationCommand { get; private set; } 
    public ICommand LoadJobErrorNotificationCommand { get; private set; } 

    private readonly IDialogService _openFileDialogService; 
    private readonly IJobListDataService _jobListDataService; 

    private string JobFilePath {get; set;} 

    public int JobListSelectedItemIndex { get; set; } 

    public Action FinishInteraction { get; set; } 

    private ObservableCollection<JobFileInfoItem> _jobFileInfoList; 

    public ObservableCollection<JobFileInfoItem> JobFileInfoList 
    { 
     get { return _jobFileInfoList; } 
     set { _jobFileInfoList = value; } 
    } 

    public JobListViewModel(IRegionManager regionManager, 
          ILog4NetLogger logger, 
          IDialogService openFileDialogSvc, 
          IJobListDataService jobListDataSvc, 
          IEventAggregator eventAggregator 
          ) 
    { 
     _regionManager = regionManager; 
     EventAggregator = eventAggregator; 

     ConfirmationRequest = new InteractionRequest<IConfirmation>(); 
     ErrorNotification = new InteractionRequest<INotification>(); 
     RaiseDeleteJobConfirmationCommand = new DelegateCommand(RaiseDeleteJobFromListConfirmation); 
     RaiseLoadJobConfirmationCommand = new DelegateCommand(RaiseLoadJobConfirmation); 
     LoadJobErrorNotificationCommand = new RelayCommand(LoadJobErrorNotification); 
     _openFileDialogService = openFileDialogSvc; 
     _jobListDataService = jobListDataSvc; 
     _logger = logger.GetLog4NetLogger(); 

     AppEvents.MachineStatus.Event += MachineStatusHandler; 
     AppEvents.JobFileReady.Event += JobFileReadyHandler; 

     LoadJobFileInfoList(); 
    } 

    public JobListViewModel() { } 

    public string Describe(string preface = "") 
    { 
     return preface + " JobListViewModel"; 
    } 

    public log4net.ILog log 
    { 
     get { return _logger; } 
    } 

    private void LoadJobErrorNotification(object errMsg) 
    { 
     //var vm = new ErrorDialogViewModel((string)errMsg); 
     var vm = new ErrorDialogViewModel() {Message = (string) errMsg}; 
     var result = DialogService.DialogService.OpenDialog(vm); 
    } 

    protected void JobFileReadyHandler(Object sender, GatedEventBase thisEvent, JobReadyArgs args) 
    { 
      Application.Current.Dispatcher.Invoke(() => LoadJobErrorNotification(args.Error)); 
     if (args.Error.Length != 0) 
     { 
     } 
     else 
     { 
      Application.Current.Dispatcher.Invoke(() => _regionManager.RequestNavigate("ViewsRegion", "BuildActivity", new NavigationParameters("Test"))); 
     } 
    } 

    protected void MachineStatusHandler(Object sender, GatedEventBase thisEvent, MachineStatusArgs args) 
    { 
     if (args.Request) 
     { 
      //CommonEvents.Processor.AddTask(new TaskEvent(this, AppEvents.MachineStatus, new MachineStatusArgs(OperationState))); 
     } 
    } 

    private void LoadJobFileInfoList() 
    { 
     var jobFileInfoList = _jobListDataService.GetJobListFilePathData(); 

     _jobFileInfoList = new ObservableCollection<JobFileInfoItem>(); 

     foreach (string jobFile in jobFileInfoList) 
     { 
      _jobFileInfoList.Add(new JobFileInfoItem(jobFile)); 
     } 
    } 

    #region AddJobToList 
    public ICommand AddJobBtnClickedCommand 
    { 
     get { return new DelegateCommand(AddJobBtnClickedMethod); } 
     //get { return new DelegateCommand<object>(LoadJobBtnClickedMethod, CanLoadJobBtnClickedMethodBeExecuted); } 
    } 

    private void AddJobBtnClickedMethod() 
    { 
     ShowOpenFileDialog(); 
    } 

    public void ShowOpenFileDialog() 
    { 
     var settings = new OpenFileDialogSettings() 
     { 
      Title = "Select Job File", 
      InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), 
      Filter = "Build File (*.amx; *.txt) |*.amx; *.txt" 
     }; 

     if (_openFileDialogService.ShowOpenFileDialog(settings)) 
     { 
      JobFilePath = settings.FileName; 
      // Does the JobFilePath already exist in the list? 
      if (_jobFileInfoList.Any(p => p.JobFileFullPath == JobFilePath)) 
      { 
       // Since the path is already in the list, just show it as selected 
       JobListSelectedItemIndex = _jobFileInfoList.FindIndex(p => p.JobFileFullPath == JobFilePath); 
      } 
      else 
      { 
       // Add it to the list 
       _jobFileInfoList.Add(new JobFileInfoItem(JobFilePath)); 

       //Persist the list items 
       List<string> jobFilePathInfo = JobInfoObsListToList(); 
       _jobListDataService.SaveJobListFilePathData(jobFilePathInfo); 
      } 
     } 
    } 
    #endregion AddJobToList 

    #region DeleteJobFromList 
    private void RaiseDeleteJobFromListConfirmation() 
    { 
     // By invoking the Raise method we are raising the Raised event and triggering any InteractionRequestTrigger that 
     // is subscribed to it. 
     // As parameters we are passing a Confirmation, which is a default implementation of IConfirmation (which inherits 
     // from INotification) provided by Prism and a callback that is executed when the interaction finishes. 
     ConfirmationRequest.Raise(
      new Confirmation { Content = "Remove this build file from the list?", Title = "Confirmation" }, 
      c => { _deleteJobConfirmationRequestResult = c.Confirmed; }); 
    } 

    public ICommand TrashCanBtnClickedCommand 
    { 
     get { return new DelegateCommand<object>(TrashCanBtnClickedMethod); } 
    } 

    private void TrashCanBtnClickedMethod(Object jobFileName) 
    { 
     RaiseDeleteJobFromListConfirmation(); 

     if (_deleteJobConfirmationRequestResult) 
     { 
      // Determine the index of the _jobFileInfoList item containing the filename 
      var listIndex = _jobFileInfoList.FindIndex(p => p.JobFileName == (string)jobFileName); 
      _jobFileInfoList.RemoveAt(listIndex); 
      var jobFilePathInfo = JobInfoObsListToList(); 
      _jobListDataService.SaveJobListFilePathData(jobFilePathInfo); 
     } 
    } 

    List<string> JobInfoObsListToList() 
    { 
     var jobFilePaths = new List<string>(); 

     foreach(JobFileInfoItem jobInfo in _jobFileInfoList) 
     { 
      jobFilePaths.Add(jobInfo.JobFileFullPath); 
     } 

     return jobFilePaths; 
    } 

    #endregion DeleteJobFromList 

    #region LoadJob 
    public ICommand LoadJobBtnClickedCommand 
    { 
     get { return new DelegateCommand<object>(LoadJobBtnClickedMethod); } 
    } 

    private void RaiseLoadJobConfirmation() 
    { 
     // By invoking the Raise method we are raising the Raised event and triggering any InteractionRequestTrigger that 
     // is subscribed to it. 
     // As parameters we are passing a Confirmation, which is a default implementation of IConfirmation (which inherits 
     // from INotification) provided by Prism and a callback that is executed when the interaction finishes. 
     ConfirmationRequest.Raise(
      new Confirmation { Content = "Load this job file?", Title = "Confirmation" }, 
      c => { _printJobConfirmationRequestResult = c.Confirmed; }); 
    } 

    private void LoadJobBtnClickedMethod(Object jobFileName) 
    { 
     RaiseLoadJobConfirmation(); 

     if (_printJobConfirmationRequestResult) 
     { 
      int listIndex = _jobFileInfoList.FindIndex(p => p.JobFileName == (string)jobFileName); 

      string jobId = Guid.NewGuid().ToString(); 

      var args = new String2Args(jobId, _jobFileInfoList[listIndex].JobFileFullPath); 
      var s = Path.GetExtension(_jobFileInfoList[listIndex].JobFileFullPath); 
      if (s != null) 
      { 
       string extension = s.ToLower(); 
       if (extension == ".txt") 
        CommonEvents.Processor.AddTask(new TaskEvent(this, AppEvents.TextDataFile, args)); 
       else 
        CommonEvents.Processor.AddTask(new TaskEvent(this, AppEvents.AMXBuildFile, args)); 
      } 
     } 
    } 
    #endregion LoadJob 
    //private bool CanLoadJobBtnClickedMethodBeExecuted(object context) 
    //{ 
    // //this is called to evaluate whether FuncToCall can be called 
    // //for example you can return true or false based on some validation logic 
    // return true; 
    //} 


    public INotification Notification { get; set; } 

    public bool IsNavigationTarget(NavigationContext navigationContext) 
    { 
     return false; 
    } 

    public void OnNavigatedFrom(NavigationContext navigationContext) 
    { 
     navigationContext.Parameters.Add("PageFrom", ToString()); 
    } 

    public void OnNavigatedTo(NavigationContext navigationContext) 
    { 

    } 
} 

}

非常感谢您的帮助

+0

如果您使用的是“RegisterTypeForNavigation”,则不需要在容器中注册'JobList'实例。 –

+0

感谢您的观察......我删除了bootstrap.cs文件中的RegisterInstance调用,但JobList视图模型的构造函数在每次导航到它时仍会被调用。 – chuckp

+0

您可以将“JobList”视图模型代码添加到问题中吗? OMG !! –

回答

0

您正在使用INavigationAware接口,并且IsNavigationTarget始终返回false。这是造成这种情况的原因。

要么改变这个基于某些逻辑返回true或false,要么一直返回true。或者,如果真的不需要,请完全删除INavigationAware的使用。

如果视图或视图模型实现了INavigationAware接口,则在导航过程中会调用IsNavigationTarget函数。如果返回true,则它使用视图或视图模型的现有实例(如果存在)。否则,它会创建一个新实例。

您可以使用传入该函数的NavigationContext来执行诸如检查Parameters集合值之类的东西,或者不基于这些值的东西,或者通过返回true来使用现有实例,或者让应用程序创建新实例视图/视图模型的返回false。

+0

OMG !!永远不会猜测INavigationAware会导致这种类型的行为。理查兹先生,非常感谢你! – chuckp

+0

任何时候,我的朋友。乐意效劳! –

+0

只是好奇......为什么使用INavigationAware会在每次视图导航时都会创建视图模型的新实例? – chuckp