Недопустимый межпоточный доступ в приложении Silverlight - PullRequest
5 голосов
/ 08 июля 2011

Я использую платформу Hammock для выполнения асинхронных вызовов служб из приложения Silverlight в службы Rest.В «завершенном» обратном вызове я обновляю ObservableCollection, которая привязана к комбинированному списку в представлении.

В обработчике события «OnPropertyChanged» создается исключение «Недопустимый межпотоковый доступ».

Это потому, что гамак не выполняет обратный вызов в потоке пользовательского интерфейса?Если нет, то почему?Казалось бы, это функциональность, которую должен обрабатывать фреймворк.Я что-то пропустил?Я уверен, что не хочу обрабатывать вызов потока пользовательского интерфейса самостоятельно в каждом завершенном обработчике.

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);
}

Спасибо

Ответы [ 3 ]

8 голосов
/ 08 июля 2011

Для связанных свойств и свойств, которые являются коллекциями (а не дочерними в наблюдаемых коллекциях), только поток OnPropertyChanged должен находиться в потоке пользовательского интерфейса.Свойства могут измениться раньше, но пользовательский интерфейс не изменит привязки, пока не будет вызван OnPropertyChanged.

Все наши ViewModels являются производными от созданной нами ViewModelBase, которая реализует вспомогательный SendPropertyChanged, как показано ниже (поэтому нам никогда не придется беспокоиться о перекрестномнарезания резьбы).

Все наши свойства notify вызывают это вместо непосредственного вызова OnPropertyChanged.

Он также предоставляет обычно полезный метод OnUiThread, поэтому вы можете выполнить произвольный код в потоке пользовательского интерфейса:

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, а) извинения и б) позор вам:)

3 голосов
/ 08 июля 2011

Hammock запускает ваш запрос в фоновом потоке, и вы абсолютно хотите выполнить его там и сами переключить переключение обратно в поток пользовательского интерфейса. В противном случае вы заблокируете поток пользовательского интерфейса, и ваше приложение будет не отвечать на запросы.

Чтобы вернуться к шагу пользовательского интерфейса, вам понадобится ручка на диспетчере. Самый простой способ получить это так:

Deployment.Current.Dispatcher.BeginInvoke(() => {
    this.MyBoundCollection = visibleData;
    OnPropertyChanged("MyBoundCollection");
});
0 голосов
/ 18 октября 2012

Мне понравилось ниже

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)
      {
      }
    }


  }

}
...