C# UWP 异步绑定



我在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)中的异步工作。过去,我使用依赖注入并抽象接口以使我的视图模型能够访问 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 中进行绑定。

最新更新