【问题标题】:Virtualisation not changing properties of new visible items虚拟化不会改变新可见项目的属性
【发布时间】:2016-07-05 10:43:16
【问题描述】:

我目前在 listView 中使用自定义 Image 对象(<Image> 对象的包装器)。当新的列表视图项可见(已实现)时,我的自定义 Image 对象的属性不会改变。

例如,如果我的列表视图(包含 30 个具有不同图像 URL 和不同文本的项目)在第一个滚动条上有 3 个项目,那么第 10 个项目与第一个项目具有相同的图像。图像按 [1-9][1-9][1-9] 的顺序重复......但令我惊讶的是,所有 30 个 listViewItems 中的文本都不同。

在调试时,我发现我的图像对象的设置器仅在前 9 个项目中被调用。有人可以阐明其他系统组件(系统图像/文本块工作正常)如何获得新的元素值吗?

相关类属性的代码sn-p:

public sealed partial class CustomImage : UserControl
{

public static readonly DependencyProperty ImageSourceStringProperty = DependencyProperty.Register("ImageSourceString", typeof(string), typeof(CustomImage), new PropertyMetadata(null, new PropertyChangedCallback(ImageSourceStringChanged)));
    public string ImageSourceString
    {
        get { return (string)GetValue(ImageSourceStringProperty); }
        set
        {
            //THIS NEVER GETS HIT FOR ITEMS AFTER 9th ITEM
            SetValue(ImageSourceStringProperty, value);
            //{More code here}
        }
    }
}

Xaml Usage
<ListView ItemsSource="{Binding}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <custom:customImage x:Name="Img" ImageSourceString="{Binding ImgPath}"/>
                    <TextBlock Grid.Column="1" Text="{Binding Name}"/>
                 </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

我是否错过了它应该如何工作?如果有不清楚的地方请告诉我,我可以澄清。

【问题讨论】:

  • 链接到一个示例项目:onedrive.live.com/… 您可以在输出窗口中看到 getter 没有被命中列表的后面部分

标签: c# listview uwp win-universal-app winrt-xaml


【解决方案1】:

依赖属性的gettersetter 不能保证运行,我们最好不要在setter 中放入任何其他代码。请注意Custom dependency properties中的注意

除特殊情况外,您的包装器实现应仅执行 GetValue 和 SetValue 操作。否则,通过 XAML 设置属性与通过代码设置属性时,您将获得不同的行为。为了提高效率,XAML 解析器在设置依赖属性时会绕过包装器;只要有可能,它就会使用依赖属性的注册表。

因此,我们可以使用ImageSourceStringChanged 方法对新值进行操作,而不是对您的属性的setter 做出反应,如下所示:

private static void ImageSourceStringChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    CustomImage currentImage = obj as CustomImage;
    string oldValue = e.OldValue as string;
    string newValue = e.NewValue as string;
    MainPage.logMsg("ImageSource = " + newValue);
    if (oldValue == null || !oldValue.Equals(newValue))
    {
        string path = newValue;
        if (string.IsNullOrEmpty(path))
        {
            Uri imageFileUri = new Uri("ms-appx:///Assets/Images/failed.png");
            currentImage.mainImage.ImageSource = new BitmapImage(imageFileUri);
        }
        else
        {
            Uri imageFileUri = null;
            try
            {
                imageFileUri = new Uri(path);
            }
            catch
            {
                imageFileUri = new Uri("ms-appx:///Assets/Images/failed.png");
            }
            if (imageFileUri != null)
            {
                currentImage.mainImage.ImageSource = new BitmapImage(imageFileUri);
            }
        }
    }
}

此外,由于您的DependencyProperty 的类型是string,因此您不需要比较OldValueNewValue,因为只有在值更改时才会调用回调。见Property changed behavior for structures and enumerations

如果 DependencyProperty 的类型是枚举或结构,即使结构的内部值或枚举值没有改变,也可以调用。这与系统原语不同,例如仅在值更改时才调用的字符串。

所以CustomImage的完整代码可能如下:

public sealed partial class CustomImage : UserControl
{
    public static readonly DependencyProperty ImageSourceStringProperty = DependencyProperty.Register("ImageSourceString", typeof(string), typeof(CustomImage), new PropertyMetadata(null, new PropertyChangedCallback(ImageSourceStringChanged)));

    public string ImageSourceString
    {
        get { return (string)GetValue(ImageSourceStringProperty); }
        set
        {
            SetValue(ImageSourceStringProperty, value);
        }
    }

    private static void ImageSourceStringChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        CustomImage currentImage = obj as CustomImage;
        string path = e.NewValue as string;
        MainPage.logMsg("ImageSource = " + path);

        if (string.IsNullOrEmpty(path))
        {
            Uri imageFileUri = new Uri("ms-appx:///Assets/Images/failed.png");
            currentImage.mainImage.ImageSource = new BitmapImage(imageFileUri);
        }
        else
        {
            Uri imageFileUri = null;
            try
            {
                imageFileUri = new Uri(path);
            }
            catch
            {
                imageFileUri = new Uri("ms-appx:///Assets/Images/failed.png");
            }
            if (imageFileUri != null)
            {
                currentImage.mainImage.ImageSource = new BitmapImage(imageFileUri);
            }
        }
    }

    public CustomImage()
    {
        this.InitializeComponent();
    }
}

【讨论】:

  • 谢谢。就像我说的,这是我第一次在我的项目中制作依赖对象。我认为它与普通 XAML 绑定的工作方式相同。
猜你喜欢
  • 2019-08-05
  • 1970-01-01
  • 2019-08-21
  • 2016-09-04
  • 2021-05-10
  • 1970-01-01
  • 2014-05-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多