繁体   English   中英

C#UWP异步绑定

[英]C# UWP Async binding

我在UWP(Windows 10)中使用绑定和异步方法遇到问题。 我有一个复选框绑定到一个布尔isDay 当我更改isDay ,该复选框也会更改其状态。

我在XAML中的代码如下所示:

IsChecked="{x:Bind isDay, Mode=TwoWay}"

在异步方法中更改isDay ,该复选框不会更改其状态。

我应该怎么做才能使这种绑定与异步方法一起工作?

以我的经验,复选框未更改的根本原因是属性更改通知未在UI线程上触发。 我相信UWP可以吞下失败,而不是抛出“从其他线程访问某些内容”的异常。

如果您已经可以轻松访问Dispatcher (您的代码隐藏或其他视图级组件),则可以执行以下操作:

private async void ClickHandler(object sender, EventArgs args)
{
    bool checked = await SomeAsyncWorkThatReturnsBool().ConfigureAwait(false);
    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => checkbox.IsChecked = checked);
}

但是,如果我没有Dispatcher怎么办?

您更有可能是因为视图模型,模型或实际上没有权限访问Dispatcher (或多个Dispatcher情况下,不能访问正确的Dispatcher另一层中的异步工作而问。 过去,我使用依赖注入并抽象化了接口,以使视图模型可以访问UI线程,但是可以说这是一种代码味道。

我当前最喜欢的方法(希望得到反馈)是在事件注册期间捕获SynchronizationContext ,并使用它发布更改事件。

public class BindableBase : INotifyPropertyChanged
{
    private readonly List<(SynchronizationContext context, PropertyChangedEventHandler handler)> _handlers = new List<...>();

    public event PropertyChangedEventHandler PropertyChanged
    {
        add => _handlers.Add((SynchronizationContext.Current, value));
        remove
        {
            var i = 0;
            foreach (var item in _handlers)
            {
                if (item.handler.Equals(value))
                {
                    _handlers.RemoveAt(i);
                    break;
                }
                i++;
            }
        }
    }

    protected Task RaisePropertyChanged(string propertyName)
    {
        var args = new PropertyChangedEventArgs(propertyName);
        var tasks = _handlers
            .GroupBy(x => x.context, x => x.handler)
            .Select(g => invokeContext(g.Key, g));
        return Task.WhenAll(tasks);

        Task invokeContext(SynchronizationContext context, IEnumerable<PropertyChangedEventHandler> l)
        {
            if (context != null)
            {
                var tcs = new TaskCompletionSource<bool>();
                context.Post(o =>
                {
                    try { invokeHandlers(l); tcs.TrySetResult(true); }
                    catch (Exception e) { tcs.TrySetException(e); }
                }, null);
                return tcs.Task;
            }
            else
            {
                return Task.Run(() => invokeHandlers(l));
            }
        }
        void invokeHandlers(IEnumerable<PropertyChangedEventHandler> l)
        {
            foreach (var h in l)
                h(this, args);
        }
    }
}

出于某种原因,通过异步方法更新值时,绑定未更新。 因此,在异步方法结束时,我只使用:

Bindings.Update();

控件将更新为最新值。

默认情况下,自动生成的XAML代码不支持等待的方法,因此您不能使用Task<T>方法在XAML中进行绑定。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM