wpf在ShowDialog上的异常,用于与后台工作者的进度对话框
本文关键字:工作者 后台 对话框 ShowDialog 异常 wpf 用于 | 更新日期: 2023-09-27 17:49:51
我按照我在网上看到的一个例子创建了一个进度对话框(下面的代码),在主线程中,我调用
ProgressDialog pd = new ProgressDialog("Loading File: ", VCDFileName);
pd.Owner = Application.Current.MainWindow;
pd.WindowStartupLocation = WindowStartupLocation.CenterOwner;
ModuleHierarchyVM.TopLevelModules.Clear();
VCDData TempVCDOutput = null;
Action handler = delegate
{
VCDParser.ParseVCDFileForAllPorts(VCDFileName, this, pd.Worker, ModuleHierarchyVM.TopLevelModules, out TempVCDOutput);
};
pd.SetBGWorkerDelegate(handler);
pd.ShowDialog();
我认为错误发生在传递给委托的函数中。我想我得到了两个异常(一个在每个线程上可能?)第一个说,
TargetInvocationException未处理。异常已被调用的目标抛出。
我认为这个异常是由UI线程抛出的,因为有时在异常显示之前传递给委托的函数内部遇到了断点,有时没有。
然后在按下f5一段时间后,并且在后台执行函数时经历了许多断点,
我最终回到UI线程和pd.ShowDialog(),得到这个异常:
InvalidOperationException未处理。ShowDailog只能在隐藏窗口中调用。
我放了一堆try catch块来尝试捕获异常,如果它发生在传递给委托的函数内部,但我没有捕获它。
进度对话框中的代码
public partial class ProgressDialog : Window
{
BackgroundWorker _worker;
public BackgroundWorker Worker
{
get { return _worker; }
}
public string MainText
{
get { return MainTextLabel.Text; }
set { MainTextLabel.Text = value; }
}
public string SubText
{
get { return SubTextLabel.Text; }
set { SubTextLabel.Text = value; }
}
public bool IsCancellingEnabled
{
get { return CancelButton.IsVisible; }
set { CancelButton.Visibility = value ? Visibility.Visible : Visibility.Collapsed; }
}
private bool _Cancelled = false;
public bool Cancelled
{
get { return _Cancelled; }
}
private Exception error = null;
public Exception Error
{
get { return error; }
}
private object result = null;
public object Result
{
get { return result; }
}
/// <summary>
/// Represents the method that will handle the DoWork event from the backgroundowkrker
/// </summary>
private Action workerCallback;
private object BackgroundWorkerArgument;
public ProgressDialog(string MainText, string SubText)
: this()
{
this.MainText = MainText;
this.SubText = SubText;
}
public ProgressDialog()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(ProgressDialog_Loaded);
_worker = new BackgroundWorker();
_worker.WorkerReportsProgress = true;
_worker.WorkerSupportsCancellation = true;
_worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
_worker.ProgressChanged += new ProgressChangedEventHandler(_worker_ProgressChanged);
_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_worker_RunWorkerCompleted);
Closing += new CancelEventHandler(ProgressDialog_Closing);
}
void ProgressDialog_Loaded(object sender, RoutedEventArgs e)
{
_worker.RunWorkerAsync(BackgroundWorkerArgument);
}
void ProgressDialog_Closing(object sender, CancelEventArgs e)
{
//if progress dialog is open
if (DialogResult == null)
{
MessageBoxResult messageBoxResult = System.Windows.MessageBox.Show("Are you sure you wish to cancel?",
"Confirmation", System.Windows.MessageBoxButton.YesNo);
if (messageBoxResult == MessageBoxResult.Yes)
{
if (_worker.IsBusy)
{
//notifies the async thread that a cancellation has been requested.
_worker.CancelAsync();
}
DialogResult = false;
}
else
{
e.Cancel = true;
}
}
else
{
if (_worker.IsBusy)
{
//notifies the async thread that a cancellation has been requested.
_worker.CancelAsync();
}
}
}
void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (!Dispatcher.CheckAccess())
{
//run on UI thread
RunWorkerCompletedEventHandler handler = _worker_RunWorkerCompleted;
Dispatcher.Invoke(handler, null, DispatcherPriority.SystemIdle, new object[] { sender, e });
return;
}
else
{
if (e.Error != null)
{
error = e.Error;
}
else if (!e.Cancelled)
{
//assign result if there was neither exception nor cancel
result = e.Result;
}
ProgressBar.Value = ProgressBar.Maximum;
CancelButton.IsEnabled = false;
//set the dialog result, which closes the dialog
if (DialogResult == null)
{
if (error == null && !e.Cancelled)
{
DialogResult = true;
}
else
{
DialogResult = false;
}
}
}
}
void _worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (!Dispatcher.CheckAccess())
{
//run on UI thread
ProgressChangedEventHandler handler = _worker_ProgressChanged;
Dispatcher.Invoke(handler, null, DispatcherPriority.SystemIdle, new object[] { sender, e });
return;
}
else
{
if (e.ProgressPercentage != int.MinValue)
{
ProgressBar.Value = e.ProgressPercentage;
}
}
}
void _worker_DoWork(object sender, DoWorkEventArgs e)
{
try
{
if ((_worker.CancellationPending == true))
{
//cancel the do work event
e.Cancel = true;
}
else
{
// Perform a time consuming operation and report progress.
workerCallback();
}
}
catch (Exception)
{
//disable cancelling and rethrow the exception
Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new Action(delegate { CancelButton.SetValue(Button.IsEnabledProperty, false); }), null);
throw;
}
}
public void SetBGWorkerDelegate(Action workHandler)
{
SetBGWorkerDelegate(null, workHandler);
}
public void SetBGWorkerDelegate(object argument, Action workHandler)
{
//store reference to callback handler and launch worker thread
workerCallback = workHandler;
BackgroundWorkerArgument = argument;
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
MessageBoxResult messageBoxResult = System.Windows.MessageBox.Show("Are you sure you wish to cancel?",
"Confirmation", System.Windows.MessageBoxButton.YesNo);
if (messageBoxResult == MessageBoxResult.Yes)
{
if (_worker.IsBusy)
{
//notifies the async thread that a cancellation has been requested.
_worker.CancelAsync();
}
DialogResult = false;
}
}
}
}
我建议不要在外部启动次要线程,而是在对话框本身的Loaded事件处理程序中启动。这样,您只需调用ShowDialog,其余的就会自行处理了。
找到问题了。之前我好像跳过了第一个例外。不管怎样,第一个异常有一个innerexception,它给出了实际的细节。在某个地方,我仍然从错误的线程修改我的可观察集合。