【问题标题】:Calling Awaitable Methods in Property Accessor [Windows Store Apps/Metro Apps]在属性访问器中调用 Awaitable 方法 [Windows 应用商店应用程序/Metro 应用程序]
【发布时间】:2012-11-17 16:27:41
【问题描述】:

我有一个自定义类(为了简化内容,我已经精简了代码):

public class AlbumItem
{
   public StorageFile AlbumThumbnail { get; set;}
}

当我将它绑定到 ListView 时:

<ListView.ItemTemplate>
            <DataTemplate>
                <Grid Height="100" Background="#FFabe372">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="80" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <Image Source="{Binding AlbumSource}" Margin="10" Stretch="Uniform"></Image>
                    <TextBlock Margin="20 5" Grid.Column="1" Style="{StaticResource  AlbumListViewItemStyle}" Text="{Binding AlbumDisplayText}"></TextBlock>
                </Grid>

            </DataTemplate>
</ListView.ItemTemplate>

Image 的源设置为AlbumSource,因为我曾想过将AlbumSource 实现为Get-only 属性:

public class AlbumItem
{
   public StorageFile AlbumThumbnail { get; set;}

   public BitmapImage AlbumSource
   {
       get
       {
          BitmapImage bmp = new BitmapImage();
          bmp.SetSource(await AlbumThumbnail.OpenReadAsync());
          return bmp;
       }
   }
}

正如预期的那样,我不能在访问器方法中使用await 关键字,同时我不能将属性存根声明为async 方法。

有人能指出我正确的方向吗?稍后我可能会尝试Converter。谢谢!

【问题讨论】:

    标签: c# xaml microsoft-metro winrt-xaml windows-store-apps


    【解决方案1】:

    如果您使用await,则返回类型必须是Task&lt;BitmapImage&gt;。如果您希望能够绑定到您的 XAML,则需要返回 BitmapImage,因此不能使用 await。改用 Task.Result:

    public BitmapImage AlbumSource
    {
        get
        {
           BitmapImage bmp = new BitmapImage();
           bmp.SetSource(AlbumThumbnail.OpenReadAsync().GetResults());
           return bmp;
        }
    }
    

    【讨论】:

    • 这个方法解决了我的问题,虽然 dkackman 的回答给了我另一个探索的维度,谢谢两位!但我不得不将Task.Result 更改为Task.GetResults()... 而我对SetSource 的语法错误不利(应该改为SetSource())。
    【解决方案2】:

    恕我直言,属性访问器应该总是几乎立即返回。长时间运行的操作不应在属性访问器内部执行,因为这可能会对性能产生重大影响,因为广泛认为访问器基本上是变量读取操作(即属性可以在循环中被大量访问,而不是为后续访问缓存等) )。

    我会这样做:

    private async Task SetAlbumSourceAsync()
    {
        bmp = new BitmapImage();
        var source = await AlbumThumbnail.OpenReadAsync();
        bmp.SetSource(source);
        RaisePropertyChanged("AlbumSource");
    }
    
    BitmapImage bmp;
    public BitmapImage AlbumSource
    {
        get
        {
            if (bmp == null) // might need a better sync mechanism to prevent reentrancy but you get the idea
                SetAlbumSourceAsync();
    
            return bmp;
        }
    }
    

    【讨论】:

    • 谢谢!我明白了,但弗拉维恩的方法解决了我的迫切需要。我将探索您的方法,看看我是否可以在此之后启动并工作。
    • +1 这是更正确的答案。 async 属性不存在没有技术原因;这是一个设计决策,因为“异步属性”违背了属性的概念。
    • 是的,到目前为止,我已经使用这种方法实现了我的属性,是的,它不会阻塞我的 UI!非常感谢!
    • 属性没有异步修饰符是 C# 组件模型中的一个主要缺陷。问题在于属性访问器无法在与客户端调用者相同的线程内异步调用另一个方法或 lambda 表达式。在访问器需要对异步方法进行可等待访问的情况下,这种无能会引入各种非平凡的实现复杂性。从技术上讲,get 或 set 访问器只不过是单独的方法,并在编译时作为 get_ 和 set_ 实现。 MSFT 可以而且应该纠正这个严重的缺陷。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-11
    • 1970-01-01
    • 1970-01-01
    • 2012-12-07
    • 2023-04-11
    • 1970-01-01
    相关资源
    最近更新 更多