[英]PRISM 5 : IConfirmNavigationRequest methods called more than once
[英]WPF Prism 6 View Model created more than once
我對Prism 6相對較新,並且查看了其他stackoverflow帖子以嘗試找到我的問題的答案。 我有一個視圖模塊構造函數,該結構在每次導航到頁面時都會執行。
在引導文件ConfigureContainer函數中,我具有以下聲明:
base.ConfigureContainer();
//Container.RegisterInstance<JobList>(new JobList());
Container.RegisterTypeForNavigation<JobList>("JobList");
對JobList使用Container.RegisterInstance函數似乎沒有什么區別。
JobList視圖的頂部如下所示:
<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();
}
}
JobList視圖模型如下:
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)
{
}
}
}
任何幫助是極大的贊賞
您正在使用INavigationAware
接口,並且IsNavigationTarget
始終返回false。 這就是造成這種情況的原因。
根據某種邏輯將其更改為返回true或false,或者始終使它返回true。 或者,如果確實不需要,則完全刪除對INavigationAware
的使用。
如果視圖或視圖模型實現了INavigationAware
接口,則在導航期間將調用IsNavigationTarget
函數。 如果返回true,則使用現有的視圖或視圖模型實例(如果存在)。 否則,它將創建一個新實例。
您可以使用傳遞到函數中的NavigationContext
進行操作,例如檢查Parameters
集合值或不檢查值,然后基於這些值,通過返回true使用現有實例,或讓應用創建視圖/通過返回false查看模型。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.