我有一个 Silverlight 5 浏览器应用程序。
有一个类
public class ActivityControl:UserControl {
public void LoadSubControls() {
//Creates Other UserControls, does calculations and is very slow..No refactoring..
}
}
我需要创建此类的多个实例并在运行时调用方法 LoadSubControls。
public class BasicContainer:UserControl {
public void CreateMultipleActivityControls() {
for (int i = 0; i < 1000; i++) {
ActivityControl c = new ActivityControl(); ====> I need to call this in a different thread but causes Invalid Cross Thread Exception
c.LoadSubControls();
}
}
}
有什么方法可以创建多个 UI 线程以避免无效跨线程异常?
出于性能原因,我需要多线程,因为方法调用非常慢并且 UI 卡住。
有什么方法可以在 Silverlight 中调用方法 SetSyncronizationContext
(即 [SecurityCritical])?
最佳答案
无法避免在 UI 线程上创建这些控件,但您可以利用任务并行库 (TPL) 中的 System.Threading.Tasks.Task
来允许异步操作。
我已经能够在 silverlight 5 中用这样的结构做这样的事情。在查看 Caliburn.Micro 的源代码时得到了最初的想法。
以下是适用于您想要的子集。
public interface IPlatformProvider {
/// <summary>
/// Executes the action on the UI thread asynchronously.
/// </summary>
/// <param name = "action">The action to execute.</param>
System.Threading.Tasks.Task OnUIThreadAsync(Action action);
}
这里是实现。
/// <summary>
/// A <see cref="IPlatformProvider"/> implementation for the XAML platfrom (Silverlight).
/// </summary>
public class XamlPlatformProvider : IPlatformProvider {
private Dispatcher dispatcher;
public XamlPlatformProvider() {
dispatcher = System.Windows.Deployment.Current.Dispatcher;
}
private void validateDispatcher() {
if (dispatcher == null)
throw new InvalidOperationException("Not initialized with dispatcher.");
}
/// <summary>
/// Executes the action on the UI thread asynchronously.
/// </summary>
/// <param name = "action">The action to execute.</param>
public Task OnUIThreadAsync(System.Action action) {
validateDispatcher();
var taskSource = new TaskCompletionSource<object>();
System.Action method = () => {
try {
action();
taskSource.SetResult(null);
} catch (Exception ex) {
taskSource.SetException(ex);
}
};
dispatcher.BeginInvoke(method);
return taskSource.Task;
}
}
您可以沿构造函数 DI 路径传递提供者或使用像这样的静态定位器模式。
/// <summary>
/// Access the current <see cref="IPlatformProvider"/>.
/// </summary>
public static class PlatformProvider {
private static IPlatformProvider current = new XamlPlatformProvider();
/// <summary>
/// Gets or sets the current <see cref="IPlatformProvider"/>.
/// </summary>
public static IPlatformProvider Current {
get { return current; }
set { current = value; }
}
}
现在您应该能够在不阻塞主线程和卡住 UI 的情况下进行调用
public class BasicContainer : UserControl {
public async Task CreateMultipleActivityControls() {
var platform = PlatformProvider.Current;
for (var i = 0; i < 1000; i++) {
await platform.OnUIThreadAsync(() => {
var c = new ActivityControl();
c.LoadSubControls();
});
}
}
}
如果多次调用调度程序导致任何性能问题,您可以将整个过程转移到一次异步调用。
public class BasicContainer : UserControl {
public async Task CreateMultipleActivityControls() {
var platform = PlatformProvider.Current;
await platform.OnUIThreadAsync(() => {
for (var i = 0; i < 1000; i++) {
var c = new ActivityControl();
c.LoadSubControls();
}
});
}
}
关于c# - 在非 UI 线程 Silverlight 5 浏览器应用程序中创建 UserControl,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39641615/