Ответ 1
Нельзя создавать эти элементы управления в потоке пользовательского интерфейса, но вы можете использовать System.Threading.Tasks.Task
из параллельной библиотеки задач (TPL) для обеспечения асинхронных операций.
Я смог сделать что-то подобное в 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; }
}
}
Теперь вы сможете совершать свои звонки без блокировки основного потока и замораживания пользовательского интерфейса
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();
});
}
}
}
Если выполнение нескольких вызовов диспетчера вызвало любые проблемы с производительностью, вы могли бы переместить весь процесс на один вызов acync.
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();
}
});
}
}