我按照我在网上看到的一个例子创建了一个进度对话框(下面的代码),在主线程中,我调用了
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;
}
}
}
}
答案 0 :(得分:1)
我建议不要在外部启动辅助线程,而是在对话本身的Loaded事件处理程序中启动。这样你就可以简单地调用ShowDialog,其余的则自行处理。
答案 1 :(得分:0)
发现我的问题。早些时候我想我以某种方式跳过了第一个例外。无论如何,第一个例外有一个不确定的例子,它给出了实际的细节。在某个地方,我仍在从错误的线程修改我的可观察集合。我以为我已经改变了所有这些,但仍然必须有一个