2016-09-22 5 views
11

Silverlight 5ブラウザアプリケーションがあります。UI以外のスレッドでUserControlを作成するSilverlight 5ブラウザアプリケーション

私は、このクラスのインスタンスを複数作成し、実行時にメソッドのLoadSubControlsを呼び出す必要がクラス

public class ActivityControl:UserControl { 

    public void LoadSubControls() { 
     //Creates Other UserControls, does calculations and is very slow..No refactoring.. 
    } 
} 

があります。

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])を呼び出す方法はありますか?

+1

guiにすべてのコントロールが直接表示されていますか?あなたはそれらを怠け者にすることができますか? –

+0

"LoadSubControls"メソッドでは、画像を生成するためにサブコントロールのMeasureLayoutを整理します。私はInitializeComponent()を実行すべきではないという意味ですか? – George

+0

私はまたあなたのメソッドを小さな塊に分割して、実際にコントロールをUIに配置する必要があるたびにUIスレッドにコールバックするだけです。 –

答えて

3

UIスレッドでこれらのコントロールを作成することは避けられませんが、非同期操作を可能にするために、タスク並列ライブラリ(TPL)のSystem.Threading.Tasks.Taskを利用できます。

私はこのような構造のシルバーライト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(); 
      });  
     } 
    } 
} 

を凍結することなく、あなたの呼び出しを行うことができる必要がありますが、代わりにプロセス全体を動かす可能性のあるパフォーマンスの問題を引き起こしました1つの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(); 
      }  
     }); 
    } 
} 
関連する問題