我在C#(WPF)中创建一个调用COM对象中的函数的程序。其中一些功能需要一些时间,比如返回5到10秒。如果这些调用是由UI线程进行的,那么界面就会没有响应,因此我想从辅助线程进行调用,并使用UI显示包含不确定进度条的对话框窗口。
好吧,要从辅助线程进行调用,我必须初始化其中的COM对象。麻烦的是:函数返回后,辅助线程丢失。当我需要进行另一个调用时,我必须创建一个新的(第三个)线程,COM对象不属于该线程,这会引发异常。我无法实例化一个新的COM对象,因为我依赖于先前调用所导致的状态。
我看到可能的解决方案:
提前谢谢你们!
代码示例:
private ARK.ICore ark; // COM object
private ProgressWindow progressWindow = new ProgressWindow();
public MainWindow()
{
InitializeComponent();
}
// Example of use of the COM object (assume this will be used first)
private void OpenButton_Click(object sender, RoutedEventArgs e)
{
Thread thread = new Thread(() =>
{
ark = new ARK.Core2(); // COM object initialization
ark.OpenDevice(0);
progressWindow.Dispatcher.Invoke(progressWindow.Close);
// Here the thread is lost, so I can't call the functions of ark in its own thread
});
thread.Start();
progressWindow.ShowDialog();
}
// Another example of use of the COM object (assume this will be used later)
private void InitButton_Click(object sender, RoutedEventArgs e)
{
Thread thread = new Thread(() =>
{
ark.Init(ARK.EarConstants.fLeft, null); // ark object initialized in another thread, exception thrown
progressWindow.Dispatcher.Invoke(progressWindow.Close);
});
thread.Start();
progressWindow.ShowDialog();
}
答案 0 :(得分:1)
正如你所说,解决方案是:
初始化辅助线程中的COM对象并使其空闲,等待UI线程调用。
您确实需要以您的方式创建线程,并在该线程中实例化COM对象。但是你不应该让线程死掉,你应该等待来自GUI线程的命令并处理它们。假设您使用的是.NET 4.0或更高版本,这应该可以帮助您入门:
// make this a field
BlockingCollection<Action<ARK.Core2>> queue =
new BlockingCollection<Action<ARK.Core2>>();
// initialization code, execute e.g. when application starts or main window is loaded
Thread thread = new Thread(() =>
{
var ark = new ARK.Core2(); // COM object initialization
foreach (var action in queue.GetConsumingEnumerable())
{
action(ark);
}
// cleanup ark here
});
thread.Start();
然后,要从UI线程中对COM对象执行某些操作,请执行
queue.Add(ark => ark.SomeMethod());
如果您需要更新UI,请务必致电调度员,例如:
queue.Add(ark =>
{
ark.SomeMethod();
progressWindow.Dispatcher.Invoke(progressWindow.Close);
});
完成后,想要释放COM对象并关闭线程,请调用
queue.CompleteAdding();
有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/dd267312.aspx
答案 1 :(得分:0)
使用可以将对象返回到UI线程的任务
private void MethodThatWillCallComObject()
{
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
//this will call in background thread
return this.MethodThatTakesTimeToReturn();
}).ContinueWith(t =>
{
//t.Result is the return value and MessageBox will show in ui thread
MessageBox.Show(t.Result);
}, System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext());
}
private string MethodThatTakesTimeToReturn()
{
System.Threading.Thread.Sleep(5000);
return "end of 5 seconds";
}