2015-11-09 89 views
0

我有一个ICommand需要将数据设置为UI线程上的属性。编组数据回到UI线程从异步动作

public override async void Execute(object parameter) 
{ 
    var vm = (MyVm)parameter; 
    var data = await _myDataService.GetData(); 
    vm.MyData = data; // must be set on UI Thread due to binding. 
} 

现在我想换我的电话在事件记录器(我本来想做AOP和装饰用日志记录属性的方法,但我无法弄清楚在PCL)。于是我开始像这样打包我的电话。

public override void Execute(object parameter) 
{ 
    EventLogger.LogEvent(this, 
     EventLogEntryType.Command, 
     EventLogErrorSeverity.Warning, 
     Errors.GetServiceAreaCommand_ErrorMessage, 
     async() => 
     { 
      var vm = (MyVm)parameter; 
      var data = await _myDataService.GetData(); 
      vm.MyData = data; // must be set on UI Thread due to binding. 
     }); 
} 

这里是LogEvent方法。

public static void LogEvent(object sender, 
    EventLogEntryType entryType, 
    EventLogErrorSeverity eventLogErrorSeverity, 
    string friendlyErrorMessage, 
    Action action) 
{ 
    var name = sender.GetType().Name.SplitCamelCase(); 
    var startEntry = new EventLogEntry(entryType); 
    LogEvent(string.Format("Start: {0}", name), startEntry); 

    try 
    { 
     action.Invoke(); 
    } 
    catch (Exception ex) 
    { 
     var exEntry = new EventLogEntry(EventLogEntryType.Error, friendlyErrorMessage, false, ex) 
     { 
      ErrorSeverity = eventLogErrorSeverity 
     }; 
     LogEvent(string.Format("Error: {0}", name), exEntry); 
     if (eventLogErrorSeverity == EventLogErrorSeverity.Critical) 
     { 
      throw; 
     } 
    } 
    var endEntry = new EventLogEntry(entryType); 
    LogEvent(string.Format("Finish: {0}", name), endEntry); 
} 

的问题是,它看起来好像我还是设置在后台线程而非主线程(IllegalStateException异常Android中)财产。

什么是最简洁的方式来设置数据,因为在第一个示例中正在完成,同时仍然在登录方法中包装Action


我也有过成功创建ICommand一个基类,但A)改变了方法签名CanExecuteExecute,和B)还(显然)不会延伸它的能力超越Commands

我正在寻找一种干净的方式来记录方法(BeforeExecute,AfterExecute,OnError),无论他们做什么。另外,理想的日志记录机制应该是使用拦截器,但是我的C#排版实现它的能力还不够强。

[Log(EventLogEntryType.Command, EventLogErrorSeverity.Warning, "Some Friendly Message")] 
public override async void Execute(object parameter) 
{ 
    var vm = (MyVm)parameter; 
    var data = await _myDataService.GetData(); 
    vm.MyData = data; // must be set on UI Thread due to binding. 
} 

回答

0

如果你有(注意下面)访问你的代码中的活动对象,那么你可以做;

Activity.RunOnUiThread(() => { 
    //Execute my code on UIThread here 
}); 

但它是一个如果,因为我注意到您使用的是PCL,或者使用一个已经引用的,所以我怀疑是一个共享库不会知道任何有关的活动(除非你通过那个也是)。很大程度上取决于你的应用程序结构和代码的位置,但在主要的Xamarin.Android项目中,你的意见是上述应该工作

+0

我实际上使用Xamarin.Forms,所以还有'Device.BeginInvokeOnMainThread(() => {});' –