3

我正在使用 LongListSelector 在 Windows Phone 8 上的 XAML 和 C# 中制作无限滚动提要。要显示的项目从 Web 提要加载并使用数据绑定显示,每个项目的字段之一是也从 Web 加载的图像。

图像的大小都不同,但我没有在图像控件上设置宽度或高度,只是Margin="10"为了让它填满屏幕的宽度并且是图像的正确高度。

DataTemplate 中的图像控件如下所示:

<Image Source="{Binding Source.ImageUrl}" Margin="10" Stretch="UniformToFill" />

但是,我得到一个System.Windows.LayoutCycleException提示:“检测到布局周期。布局无法完成​​。”。

这似乎是由于<Image>控件在图像下载之前放置到 LongListSelector 中的事实。然后,一旦下载了图像,<Image>控件就会调整大小,从而导致错误。如果我Height="300"<Image>控件上进行设置,则不会出现异常。

我仍然希望在图像下载之前显示提要,并且提要中可能有很多图像,因此它需要有效地使用内存。

这个问题有什么解决办法吗?

4

1 回答 1

1

应该使用 Uniform 来填充宽度而不是 UniformToFill (因为要填充的统一将尝试填充“高度”,并且由于没有定义高度,我可以看到它在回收项目时会导致问题)

也许您可以尝试限制同时加载的图像数量,例如以下代码将使用附加属性一次加载一个(您可以适应加载多个)。对于 AsyncLock,您可以使用此处的代码 (或在线搜索)

public static readonly DependencyProperty LimitedImageProperty = DependencyProperty.RegisterAttached("LimitedImage", typeof (string), typeof (LimitImageDownloadConverter), new PropertyMetadata(default(string),LimitedImagedChanged));

    public static void SetLimitedImage(UIElement element, string value)
    {
        element.SetValue(LimitedImageProperty, value);
    }

    public static string GetLimitedImage(UIElement element)
    {
        return (string) element.GetValue(LimitedImageProperty);
    }


    AsyncLock imageLock = new AsyncLock();

    private static async void LimitedImagedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Image currentImage = d as Image;
        object dataContext = currentImage.DataContext;
        string uri = e.NewValue as string;
        if (string.IsNullOrEmpty(uri))
        {
            return;
        }

            using (await imageLock.AcquireLock())
            {
                if (currentImage.DataContext != dataContext)
                {
                    //Item jhave been recycled
                    return;
                }
                await LoadImage(currentImage, uri);
            }
    }




    private static Task<bool> LoadImage(Image image, string uri)
    {
        TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
        BitmapImage bitmap = new BitmapImage(new Uri(uri));
        bitmap.ImageOpened += (send, arg) =>
        {

            tcs.SetResult(true);
        };
        bitmap.ImageFailed += (send, arg) =>
        {

            tcs.SetResult(false);
        };
        return tcs.Task;
    }

然后只需使用local:MyAttatchedProperty.LimitedImage在图像上设置图像源,而不是直接使用 ImageSource。

于 2013-09-15T17:08:19.810 回答