x:Bind 采用异步方法的转换器

x:Bind converter with async method

我在数据模板中有一个带有图像和一些 TextBlock 的 ListView。这些控件绑定来自集合对象的信息,但图像控件的 url 在文件上。我试图绑定一个字符串(这是文件的名称)并创建一个转换来检索 url.

xaml:

<ListView Name="list" ItemsSource="{x:Bind Player.PlayerHistory, Mode=OneWay}">
        <ListView.ItemTemplate>
            <DataTemplate  x:DataType="data:HistoricoPartidas">
                <Grid HorizontalAlignment="Stretch"
                      VerticalAlignment="Stretch">
                     <Image Source="{x:Bind name, Converter={StaticResource ResourceKey=ItemConvert} }" />...

转换器:

class ItemConvert: IValueConverter {
    public object Convert(object value, Type targetType, object parameter, string language) {
        string s = value.ToString(); //value is binding  from an object of a collection
        ControlFile controle = new ControlFile();//class with file handler
        Character ch = controle.get(s).Result;//return a Character from file "s"
        return ch.Icon_URL;
}

我创建了上面的代码,但它导致了死锁(.Result?)。 我的问题是是否有办法从文件中检索数据并用于图像控制以避免死锁?

panda 是对的,你真的不应该在转换器中打开文件。这样,每次调用 Convert() 时,您都会打开文件并从中读取,这会不必要地占用太多时间和资源。更不用说它会挂起您的 UI 线程并导致死锁。您应该在填充 ListView 之前或期间打开文件,从中读取 URL 列表,然后绑定到该(可观察的)集合。

如果您想坚持目前的解决方案(我强烈建议您不要这样做),请阅读 the accepted answer here,Cleary 先生完美而深入地描述了问题。

我就是这样做的:您需要将 PlayerHistory 设为项目的 ObservableCollection,以便在添加新项目或从中删除旧项目时通知 ListView。根据您的代码片段,我想您已经这样做了。你需要的第二件事是你必须让 PlayerHistory 中的项目(我们现在称它们为 HistoryViewModel)实现 INotfyPropertyChanged interface,它们必须有一个 属性(我们称它为 PictureUri),您将在您的 DataTemplate 中绑定到哪个,他们必须在此 属性 的 setter 中引发 PropertyChanged 事件。 这些写在代码中:

class HistoryViewModel : INotifyPropertyChanged
{
    private Uri _pictureUri;

    public Uri PictureUri
    {
        get
        {
            return _pictureUri;
        }
        set
        {
            if (value == _pictureUri)
                return;

            _pictureUri = value;

            RaisePropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void RaisePropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

那么您的 DataTemplate 将如下所示:

 <DataTemplate x:DataType="data:HistoryViewModel ">
            <Grid HorizontalAlignment="Stretch"
                  VerticalAlignment="Stretch">
                 <Image Source="{Binding PictureUri}" /> ...

这样,每当您更新支持 ViewModel 的 PictureUri 属性 时,由于数据绑定,ListView 的项目也会自动更新。