c# - 在非 UI 线程 Silverlight 5 浏览器应用程序中创建 UserControl

标签 c# multithreading silverlight silverlight-5.0

我有一个 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/

相关文章:

c# - Windows服务设计

c# - asp.net 如何在 HTML 表格中显示数据

c# - 将 ManualResetEvent 包装为等待任务

C# ThreadPool 等待结果

silverlight - 在 PagedCollectionView 中隐藏和重新排序列

c# - 更改表中记录的排名

c# - C# 中的 SHA1 哈希是否会永远为给定字符串返回相同的值?

c# - 提高 C# 代码的性能

silverlight - Windows Phone - 依赖属性

c# - 如何在 Silverlight 中创建与 .NET 中工作方式相同的 GetEnumValues 扩展方法?