5

Hammock フレームワークを使用して、Silverlight アプリケーションから Rest サービスへの非同期サービス呼び出しを行っています。「完了」コールバックでは、ビューのコンボボックスにバインドされている ObservableCollection を更新しています。

「OnPropertyChanged」イベント ハンドラーで「無効なクロススレッド アクセス」例外がスローされています。

これは、Hammock が UI スレッドでコールバックを実行していないためですか? そうでない場合、なぜですか?それは、フレームワークが処理する必要がある機能のようです。何か不足していますか?完了した各ハンドラーで自分で UI スレッドの呼び出しを処理したくないことは確かです。

public void LoadMyData()
{
    var request = new RestRequest();
    request.Path = "MyRestUrlText";

    var callback = new RestCallback(
      (restRequest, restResponse, userState) =>
      {
        var visibleData = new ObservableCollection<MyDataType>();

        var myData = JsonConvert.DeserializeObject<MyDataType[]> restResponse.Content);

        foreach (var item in myData)
            visibleData .Add(item);

        this.MyBoundCollection = visibleData;
        OnPropertyChanged("MyBoundCollection");
    });

    var asyncResult = _restClient.BeginRequest(request, callback);
}

ありがとう

4

3 に答える 3

8

バインドされたプロパティとコレクションである(監視可能なコレクションの子ではない)プロパティの場合、UIスレッドに存在する必要があるのはOnPropertyChangedのみです。プロパティは以前に変更できますが、UIはOnPropertyChangedが呼び出されるまでバインディングを変更しません。

すべてのViewModelは、以下のようなヘルパーSendPropertyChangedを実装する作成したViewModelBaseから派生しています(したがって、クロススレッドについて心配する必要はありません)。

すべての通知プロパティは、OnPropertyChangedを直接呼び出す代わりに、それを呼び出します。

また、一般的に便利なOnUiThreadメソッドを公開しているため、UIスレッドで任意のコードを実行できます。

protected delegate void OnUiThreadDelegate();

public event PropertyChangedEventHandler PropertyChanged;

public void SendPropertyChanged(string propertyName)
{
    if (this.PropertyChanged != null)
    {
        this.OnUiThread(() => this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)));
    }
}

protected void OnUiThread(OnUiThreadDelegate onUiThreadDelegate)
{
    if (Deployment.Current.Dispatcher.CheckAccess())
    {
        onUiThreadDelegate();
    }
    else
    {
        Deployment.Current.Dispatcher.BeginInvoke(onUiThreadDelegate);
    }
}

MVVMを使用していない場合は、a)謝罪およびb)恥ずべきこと:)

于 2011-07-08T12:33:44.260 に答える
3

Hammock はバックグラウンド スレッドでリクエストを実行しています。あなたは絶対にバックグラウンド スレッドでリクエストを実行し、UI スレッドへの切り替えを自分で処理したいと考えています。そうしないと、UI スレッドがブロックされ、アプリケーションが応答しなくなります。

UI トレッドに戻すには、Dispatcher にハンドルが必要です。それを取得する最も簡単な方法はそのようなものです

Deployment.Current.Dispatcher.BeginInvoke(() => {
    this.MyBoundCollection = visibleData;
    OnPropertyChanged("MyBoundCollection");
});
于 2011-07-08T12:05:19.190 に答える
0

私は以下のようにしました

namespace IdleStateDetection
{

  public partial class App : Application
  {

    private bool idle = true;

    private System.Threading.Timer _sessionTimeOutTimer = null;

    public App()
    {
      this.Startup += this.Application_Startup;
      this.Exit += this.Application_Exit;
      this.UnhandledException += this.Application_UnhandledException;

      Application.Current.RootVisual.MouseMove += new MouseEventHandler(RootVisual_MouseMove);
      Application.Current.RootVisual.KeyDown += new KeyEventHandler(RootVisual_KeyDown);

      _sessionTimeOutTimer = new Timer(SessionTimeOutCheck, null, 20000, 60000);
      InitializeComponent();
    }

    private void Application_Startup(object sender, StartupEventArgs e)
    {

      this.RootVisual = new MainPage();
    }


    void RootVisual_KeyDown(object sender, KeyEventArgs e)
    {
      idle = false;

    }

    void RootVisual_MouseMove(object sender, MouseEventArgs e)
    {
      idle = false;

    }

    private void SessionTimeOutCheck(object state)
    {
      if (Deployment.Current.Dispatcher.CheckAccess())
      {
        ShowMessage();
      }
      else
      {
        Deployment.Current.Dispatcher.BeginInvoke(()=>{ShowMessage();});
      }

    }

    private void ShowMessage()
    {
      if (idle == true)
      {
        MessageBox.Show("Idle");
      }
    }

    private void Application_Exit(object sender, EventArgs e)
    {

    }

    private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
    {
      // If the app is running outside of the debugger then report the exception using
      // the browser's exception mechanism. On IE this will display it a yellow alert 
      // icon in the status bar and Firefox will display a script error.
      if (!System.Diagnostics.Debugger.IsAttached)
      {

        // NOTE: This will allow the application to continue running after an exception has been thrown
        // but not handled. 
        // For production applications this error handling should be replaced with something that will 
        // report the error to the website and stop the application.
        e.Handled = true;
        Deployment.Current.Dispatcher.BeginInvoke(delegate { ReportErrorToDOM(e); });
      }
    }

    private void ReportErrorToDOM(ApplicationUnhandledExceptionEventArgs e)
    {
      try
      {
        string errorMsg = e.ExceptionObject.Message + e.ExceptionObject.StackTrace;
        errorMsg = errorMsg.Replace('"', '\'').Replace("\r\n", @"\n");

        System.Windows.Browser.HtmlPage.Window.Eval("throw new Error(\"Unhandled Error in Silverlight Application " + errorMsg + "\");");
      }
      catch (Exception)
      {
      }
    }


  }

}
于 2012-10-18T18:16:44.473 に答える