2016-09-22 12 views
11

Silverlight 5 브라우저 응용 프로그램이 있습니다.UI가 아닌 스레드에서 UserControl 만들기 Silverlight 5 브라우저 응용 프로그램

는 클래스 I이 클래스의 여러 인스턴스를 생성하고 런타임에 메서드 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"메서드에서 이미지를 생성하기 위해 하위 컨트롤의 Measure LayoutLayout을 측정합니다. 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(); 
      });  
     } 
    } 
} 

을 메인 스레드를 차단하고 동결하지 않고 통화를 할 수 있어야한다 하나의 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(); 
      }  
     }); 
    } 
}