c# - 虚拟化不改变新可见项目的属性

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

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

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

在调试时,我发现我的图像对象的 setter 仅针对前 9 个项目被调用。有人可以阐明其他系统组件(系统图像/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>

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

最佳答案

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

In all but exceptional circumstances, your wrapper implementations should perform only the GetValue and SetValue operations. Otherwise, you'll get different behavior when your property is set via XAML versus when it is set via code. For efficiency, the XAML parser bypasses wrappers when setting dependency properties; whenever possible, it uses the registry of dependency properties.

因此,我们可以使用 ImageSourceStringChanged 方法对新值进行操作,而不是在属性的 setter 中使用react,如下所示:

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 .

If the type of a DependencyProperty is an enumeration or a structure, the may be invoked even if the internal values of the structure or the enumeration value did not change. This is different from a system primitive such as a string where it only is invoked if the value changed.

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

关于c# - 虚拟化不改变新可见项目的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36088429/

相关文章:

c# - 如何为scaletransform和rotatetransform设置不同的原点中心?

android - 显示具有不同格式条目的 ListView

android listview OpenGLRenderer 和纹理问题?

c# - 向下键上的 UWP 文本框光标功能

c# - 如何在 Windows 10 Phone 的 Windows 通用应用程序中设置触摸拖动?

c# - DryIoC - 在解析时指定一些构造函数参数

c# - 未找到 VisualStateGroups?

c# - 在自己的控制中传递验证错误

java - 如何为使用 setListAdapter 填充的 Listview 设置主题

javascript - HIdDevice.fromIdAsync 始终返回 null