我在 UWP (Windows 10) 中遇到绑定(bind)和异步方法的问题。我有一个绑定(bind)到一个 bool 值 isDay
的复选框。当我更改 isDay
时,复选框也会更改其状态。
我的 XAML 代码如下所示:
IsChecked="{x:Bind isDay, Mode=TwoWay}"
当在异步方法中更改 isDay
时,复选框不会更改其状态。
我应该怎么做才能使此绑定(bind)与异步方法一起使用?
最佳答案
根据我的经验,复选框未更改的根本原因是未在 UI 线程上触发属性更改通知。我相信 UWP 会吞下失败而不是抛出关于“从不同线程访问某些东西”的异常。
如果您已经可以轻松访问 Dispatcher
(您的代码隐藏或其他 View 级组件),那么您可以执行以下操作:
private async void ClickHandler(object sender, EventArgs args)
{
bool checked = await SomeAsyncWorkThatReturnsBool().ConfigureAwait(false);
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => checkbox.IsChecked = checked);
}
但是如果我没有 Dispatcher
怎么办?
更有可能的是,您问的原因是 View 模型、模型或实际上无法访问 Dispatcher
(或正确的 Dispatcher
当有多个时)。过去,我使用过依赖注入(inject) 并抽象化接口(interface),让我的 View 模型能够访问 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);
}
}
}
关于C# UWP 异步绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41484994/