【问题标题】:Marshalling data back to UI Thread from within Async Action从异步操作中将数据编组回 UI 线程
【发布时间】:2015-11-09 23:45:42
【问题描述】:

我有一个需要将数据设置到 UI 线程上的属性的 ICommand。

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

问题在于,我似乎仍在后台线程而不是主线程上设置属性(Android 中的 IllegalStateException)。

在第一个示例中设置数据的最简洁方法是什么,同时仍将 Action 包装在日志记录方法中?


我也成功地为 ICommand 创建了一个基类,但是它 A) 更改了 CanExecuteExecute 的方法签名,并且 B) 它也(显然)没有将它的功能扩展到 @987654328 之外@。

我正在寻找一种干净的方式来记录方法(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.
}

【问题讨论】:

    标签: c# logging xamarin aop portable-class-library


    【解决方案1】:

    如果您在代码中可以访问 Activity 对象(请注意以下事项),那么您可能可以这样做;

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

    但这是一个 if,因为我注意到您正在使用 PCL,或者已经使用 PCL 进行了引用,所以我怀疑共享库不会知道有关 Activity 的任何信息(除非您也通过)。很大程度上取决于您的应用程序结构和此代码的位置,但在您的上述视图所在的主 Xamarin.Android 项目中应该可以工作

    【讨论】:

    • 我实际上在使用 Xamarin.Forms 所以还有Device.BeginInvokeOnMainThread(()=>{});
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-02
    • 2010-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多