2017-04-18 55 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