2016-03-18 1 views
4

В настоящее время я использую собственный объект изображения (обертка вокруг объекта <Image>) в спискеView. Свойства моего пользовательского объекта изображения не изменяются, когда новый элемент списка виден (реализован).Виртуализация не меняя свойств новых видимых элементов.

Например, если мой список (содержащий 30 элементов с разными URL-адресами изображений и другим текстом) имеет 3 элемента в первом прокрутке, то 10-й элемент имеет то же изображение, что и 1-й элемент. Образы повторяются в порядке [1-9] [1-9] [1-9]. Но, к моему удивлению, текст во всех 30 списках элементов отличается.

При отладке я обнаружил, что сеттер для моего объекта изображения вызывается только для первых 9 элементов. Может ли кто-нибудь пролить свет на то, как другие системные компоненты (System Image/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> 

Я пропускаю, как она должна работать? Если что-то неясно, сообщите мне, я могу уточнить.

+0

Ссылка на образец проекта: https://onedrive.live.com/redir?resid=1E821DC34DAB55E6!93133&authkey=!ADgUGdiBejywGCE&ithint=file% 2czip В окне вывода вы можете увидеть, что геттер не попадает в последующую часть списка –

ответ

2

Нельзя запускать свойства зависимостей и setter, поэтому лучше не указывать другой код в 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, вы не нужно сравнивать OldValue и NewValue, так как обратный вызов активируется только при изменении значения. См. 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(); 
    } 
} 
+0

Спасибо. Как я уже сказал, это первый раз, когда я создаю объекты зависимостей в своем проекте. Я предположил, что он будет работать так же, как и обычная привязка XAML. –