虚拟化不会更改新可见项的属性

时间:2016-03-18 15:34:51

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

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

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

在调试时,我发现只为前9个项目调用了我的图像对象的setter。有人可以了解其他系统组件(系统映像/ TextBlock正常工作)如何获得新的元素值?

相关类属性的代码段:

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>

我错过了它应该如何工作?如果有什么不清楚请告诉我,我可以澄清。

1 个答案:

答案 0 :(得分:3)

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

  

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

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

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();
    }
}