DisplayMemberPath при использовании ItemsPanelTemplate

У меня есть список объектов типа SomeObject, который определяется как:

public struct SomeObject
{
  public SomeObject(int id, string imgPath)
  {
    Id = id;
    ImagePath = imgPath;
  }

  public int Id;
  public string ImagePath;
}

Я хочу отобразить эти объекты в списке, который показывает одно изображение для каждого объекта и размещает их в макете плитки. ItemsTemplate - это просто изображение. ItemsPanelTemplate - это панель TilePanel.

Когда я использую только строки (пути к изображениям) в качестве элементов списка вместо элементов SombeObject, все работает, и изображения отображаются правильно.

<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled"
         SelectionMode="Extended"
         SelectionChanged="OnItemSelectionChanged"
         ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type controls:VerticalTileBox}},
                    Path=SomeObjectsCollectionView, UpdateSourceTrigger=PropertyChanged}"
         >
  <ListBox.ItemTemplate>
  <DataTemplate>
      <Image Source ="{Binding}" 
                 VerticalAlignment="Center" HorizontalAlignment="Center" Stretch="Uniform" >            
      </Image>
   </DataTemplate>
  </ListBox.ItemTemplate>
  <ListBox.ItemsPanel>
    <ItemsPanelTemplate>
      <controls:VirtualizingTilePanel ChildSize="{Binding 
        RelativeSource={RelativeSource AncestorType={x:Type controls:VerticalTileBox}},
                    Path=ItemSize, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" />
    </ItemsPanelTemplate>
  </ListBox.ItemsPanel>
  <ListBox.ItemContainerStyle>
    <Style TargetType="ListBoxItem">
      <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
      <Setter Property="VerticalContentAlignment" Value="Stretch"/>
      <Setter Property="Padding" Value="0"/>
    </Style>
  </ListBox.ItemContainerStyle>
</ListBox>

При использовании элементов SomeObject этот код дает мне список плиток, но изображения не отображаются.

Ошибка System.Windows.Data: 40: Ошибка пути BindingExpression: свойство 'ImagePath' не найдено в 'объекте' ''SomeObject' (HashCode=1739718653)'. BindingExpression:Path=ImagePath; DataItem='SomeObject' (HashCode=1739718653); целевым элементом является "Изображение" (Name=''); Свойство target - "Source" (тип "ImageSource")

Это ожидаемо, поскольку я не сказал элементу управления, что именно отображать (какое свойство SomeObject). Использование DisplayMemberPath в дополнение к ItemsPanelTemplate не работает, так как мне установить свойство, которое будет использоваться для отображения на изображении?

Спасибо за вашу помощь!

редактировать: @ nkoniishvt

Это действительно похоже на правильный способ сделать это, но я не могу заставить его работать должным образом. Что я делаю неправильно?

Я добавил этот DP в код UserControl:

public static readonly DependencyProperty ItemsTemplateProperty =
  DependencyProperty.Register("ItemsTemplate", 
  typeof(DataTemplate),
  typeof(VerticalTileBox),
  new PropertyMetadata(null));

public DataTemplate ItemsTemplate
{
  get {return (DataTemplate)GetValue(ItemsTemplateProperty);}
  set {SetValue(ItemsTemplateProperty, value);}
}

и изменил xaml следующим образом:

<ListBox 
         ScrollViewer.HorizontalScrollBarVisibility="Disabled"
         SelectionMode="Extended"
         SelectionChanged="OnItemSelectionChanged"
         ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type controls:VerticalTileBox}},
                    Path=ItemCollection, UpdateSourceTrigger=PropertyChanged}"
       ItemTemplate="{Binding RelativeSource={RelativeSource AncestorType={x:Type controls:VerticalTileBox}},
                    Path=ItemsTemplate, UpdateSourceTrigger=PropertyChanged}"
       >
   <ItemsPanelTemplate>
      <controls:VirtualizingTilePanel ChildSize="{Binding 
        RelativeSource={RelativeSource AncestorType={x:Type controls:VerticalTileBox}},
                    Path=ItemSize, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" />
  </ItemsPanelTemplate>
  </ListBox.ItemsPanel>
  <ListBox.ItemContainerStyle>
    <Style TargetType="ListBoxItem">
      <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
      <Setter Property="VerticalContentAlignment" Value="Stretch"/>
      <Setter Property="Padding" Value="0"/>
    </Style>
  </ListBox.ItemContainerStyle>
</ListBox>

Шаблон данных определяется так:

  <DataTemplate x:Name="SomeImageItemTemplate"   DataType="utilities:SomeObject">
    <Image Source ="{Binding Path=ImagePath}" 
                 VerticalAlignment="Center" HorizontalAlignment="Center" Stretch="Uniform" />
  </DataTemplate>

И общая вещь используется на мой взгляд, как это:

  <ctrls:VerticalTileBox Source="{Binding ImageListView, UpdateSourceTrigger=PropertyChanged}" ItemsTemplate="{DynamicResource SomeImageItemTemplate}"/>

В результате отображаются плитки, но все они пусты, за исключением имен классов объектов (SomeObject).

1 ответ

Решение

Вы не можете иметь общий DataTemplate, если данные, которые вы указали в качестве ItemsSource вашего ListBox, неизвестны и ваш UserControl должен оставаться универсальным.

Вместо этого вы должны позволить потребителю вашего UserControl предоставить DataTemplate, либо в UserControl.Resources, либо в DP DataTemplate DP, который необходимо создать и привязать к ItemTemplate ListBox.

Панели не должны указывать, как отображается ребенок, только где и насколько он должен быть большим.

Другие вопросы по тегам