x: 使用异步方法绑定转换器

本文关键字:绑定 转换器 异步方法 | 更新日期: 2023-09-27 18:29:49

我有一个ListView,在datatamplate中有一个Image和一些TextBlock。这些控件绑定来自集合对象的信息,但图像控件的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?)。我的问题是,是否有一种方法可以从文件中检索数据,用于图像控制以避免死锁?

x: 使用异步方法绑定转换器

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

如果你想坚持你目前的解决方案(我强烈建议你不要这样做),请阅读这里的公认答案,克利里先生完美而深入地描述了这个问题。

我就是这么做的:你需要让PlayerHistory成为一个项目的ObservableCollection,这样当添加新项目或从中删除旧项目时,ListView就会收到通知。根据你的代码片段,我想你已经这样做了。您需要的第二件事是,您必须使PlayerHistory中的项(现在我们称它们为HistoryViewModel)实现INotfyPropertyChanged接口,它们必须有一个属性(我们称之为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 x:DataType="data:HistoryViewModel ">
            <Grid HorizontalAlignment="Stretch"
                  VerticalAlignment="Stretch">
                 <Image Source="{Binding PictureUri}" /> ...

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