我有一个UserControl,其中包含一个使用大量转换器显示值的大表。我试图在具有Indeterminate状态的新窗口中显示ProgressBar,该窗口在触发UserControl Loaded事件时自动关闭。
这是我的UserControl的反码中的线程创建:
Thread progressBarThread = new Thread(new ThreadStart(delegate {
ProgressBarWindow progressBarWindow = new ProgressBarWindow();
progressBarWindow.IsIndeterminate = true;
progressBarWindow.LaunchProgressBarInBackground();
progressBarWindow.ShowDialog();
}));
progressBarThread.SetApartmentState(ApartmentState.STA);
progressBarThread.Start();
this.Loaded += (sender, e) => { Dispatcher.FromThread(progressBarThread).InvokeShutdown(); };
这段代码正在“工作”,它正在打开progressBarWindow但是当我使用InvokeShutdown关闭线程时(最丑陋的方式来做,我同意)。问题是来自我的backgroundWorker的DoWork。
这是DoWork功能:
private void BackgroundWorker_WaitUntilShouldStop(object sender, DoWorkEventArgs e)
{
// Do not access the form's BackgroundWorker reference directly.
// Instead, use the reference provided by the sender parameter.
BackgroundWorker bw = sender as BackgroundWorker;
// Start the time-consuming operation.
while (!bw.CancellationPending)
{
Thread.Sleep(500);
}
}
我想调用ProgressBarWindow中包含的函数来阻止DoWork运行并使用以下方法正常关闭ProgressBarWindow:
progressBar.StopProgressBarInBackground();
此方法正在调用backgroundWorker.CancelAsync();
这将导致backgroundWorker终止并且progressBarWindow自动关闭。
但我无法访问progressBarThread中的progressBar。我尝试使用以下方式传递UserControl:
progressBarThread.Start(this);
this
是主窗口。
尝试从主线程传递变量时,抛出此错误:
An exception of type 'System.InvalidOperationException' occurred in WindowsBase.dll but was not handled in user code Additional information: The calling thread cannot access this object because a different thread owns it.
有人在没有使用myThread.InvokeShutdown()的情况下有一个很好的正确方法吗?
修改1:
我使用volatile变量找到了解决问题的方法:
volatile bool _isLoaded;
void CreateAndStopProgressBarWhenIsLoaded()
{
Thread progressBarThread= new Thread(new ThreadStart(
{
Controls.ProgressBar.ProgressBar progressBar = new Controls.ProgressBar.ProgressBar();
progressBar.IsIndeterminate = true;
progressBar.LaunchProgressBarInBackground();
DispatcherTimer dispatcherTimer = new DispatcherTimer();
dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += (sender, e) => {
if (_isLoaded)
progressBar.StopProgressBarInBackground();
};
// Try to stop `progressBar` every 500 ms
dispatcherTimer.Interval = TimeSpan.FromMilliseconds(500);
dispatcherTimer.Start();
progressBar.ShowDialog();
// Will only be reached once progressBar.ShowDialog(); returns
dispatcherTimer.Stop();
}));
progressBarThread.SetApartmentState(ApartmentState.STA);
progressBarThread.Start();
this.Loaded += (sender, e) => {
_isLoaded = this.IsLoaded;
progressBarThread.Join(); // Wait for progressBarThread to end
};
}
现在问题是你有更好的解决方案吗?
编辑2:
感谢@AlexSeleznyov:
,这是我的最终解决方案 void CreateAndStopProgressBarWhenIsLoaded()
{
Controls.ProgressBar.ProgressBar pb = null;
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
Thread progressBarThread = new Thread(new ThreadStart(delegate
{
Controls.ProgressBar.ProgressBar progressBar = new Controls.ProgressBar.ProgressBar();
pb = progressBar;
manualResetEvent.Set();
progressBar.IsIndeterminate = true;
progressBar.LaunchProgressBarInBackground();
progressBar.ShowDialog();
}));
progressBarThread.SetApartmentState(ApartmentState.STA);
progressBarThread.Start();
this.Loaded += (sender, e) => {
pb.Dispatcher.Invoke(delegate {
manualResetEvent.WaitOne();
pb.StopProgressBarInBackground();
});
progressBarThread.Join();
};
}
答案 0 :(得分:0)
我认为你可以在ProgressBarWindow中使用BackgroundWorker.RunWorkerCompleted - 当你取消backgroundWorker时会调用它。
private void backgroundWorker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
//close the window
}
}
答案 1 :(得分:0)
您可以尝试这种方法,缓存@JoinTable
实例,然后从另一个线程使用它。 ProgressBar
根除了Dispatcher.Invoke
我在评论中提到的需求。
CheckAccess
}