Отображение изображений в ListView (или что-то лучше!) в WPF MVVM с использованием привязки данных
Я пытаюсь отобразить некоторые изображения в ListView и не удалось. Я использую WPF MVVM, а ListView-это пережиток от простого отображения костюмов и данных ранга. (См. мой предыдущий пост: MVVM в WPF-как предупредить ViewModel об изменениях в модели... или должен? если вы заинтересованы!) То есть я мог бы использовать что-то другое, кроме ListView (если это совет), но я все равно хотел бы знать, как это сделать с ListView, предполагая, что это выполнимо. Моя собственность я привязка к в ViewModel:
public ObservableCollection<Image> PlayerCardImages{
get{
ObservableCollection<Image> results = new ObservableCollection<Image>();
foreach (CardModel card in PlayerCards)
{
Image img = new Image();
BitmapImage bi3 = new BitmapImage();
bi3.BeginInit();
// TODO: Pick card based on suit/rank. Just get 1 image working now
bi3.UriSource = new Uri("diamond-1.png", UriKind.Relative);
bi3.EndInit();
img.Stretch = Stretch.Fill;
img.Source = bi3;
results.Add(img);
}
return results;
}
}
в своем XAML код, который я использую:
<Window.Resources>
<DataTemplate x:Key="ImageCell">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding PlayerCardImages}" Width="200" Height="200" Stretch="Fill" ToolTip="Add tooltip"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<StackPanel Orientation="Vertical">
<Label Content="Player Cards"/>
<ListView Name="lvwTitles" ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True"
SelectionMode="Single" ItemTemplate="{StaticResource ImageCell}" Height="59">
</ListView>
</StackPanel>
эту идею бесстыдно украли у:WPF-привязка изображений по горизонтали к ListView однако, он даже не кажется databind, о чем свидетельствует моя точка останова в PlayerCardImages не попадает.
Я также попробовал следующий XAML с несколько большей удачей:
<StackPanel Orientation="Vertical">
<Label Content="Player Cards"/>
<ListView
AlternationCount="2"
DataContext="{StaticResource PlayerCardsGroups }"
ItemsSource="{Binding}"
>
<ListView.GroupStyle>
<StaticResourceExtension
ResourceKey="CardGroupStyle"
/>
</ListView.GroupStyle>
<ListView.View>
<GridView>
<GridViewColumn>
<Image Height="50" Width="40"></Image>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
<Window.Resources>
<CollectionViewSource x:Key="PlayerCardsGroups"
Source="{Binding Path=PlayerCardImages}">
</CollectionViewSource>
<GroupStyle x:Key="CardGroupStyle">
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock
x:Name="txt"
Background="{StaticResource Brush_HeaderBackground}"
FontWeight="Bold"
Foreground="White"
Margin="1"
Padding="4,2,0,2"
Text="Cards"
/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
<Style x:Key="CardItemStyle" TargetType="{x:Type ListViewItem}">
<!--
Stretch the content of each cell so that we can
right-align text in the Total Sales column.
-->
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<!--
Bind the IsSelected property of a ListViewItem to the
IsSelected property of a CustomerViewModel object.
-->
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ItemsControl.AlternationIndex" Value="1" />
<Condition Property="IsSelected" Value="False" />
<Condition Property="IsMouseOver" Value="False" />
</MultiTrigger.Conditions>
<Setter Property="Background" Value="#EEEEEEEE" />
</MultiTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
этот код определенно проходит через databinding-my точка останова в начале программы и каждый раз, когда элементы добавляются в коллекцию. Но изображения не отображаются. Вместо того, чтобы мучить вас больше XAML, который не работает, возможно, я мог бы попросить кого-то указать мне на некоторые код/примеры/документы, которые показывают, как связать список изображений с ListView (или другим элементом управления, если вы действительно считаете, что ListView неуместен). Обратите внимание, что моя коллекция-это то, к чему я привязан. Я замечаю, что со многими примерами они привязаны к подсвойство. Т. е. у них может быть коллекция альбомов, и для каждого альбома они привязываются к его свойству image (см.:отображение элементов в виде изображений в WPF ListView).
любые идеи или помощь будет высоко ценится.
-Дэйв
дополнительная информация.
основываясь на предложениях Клеменса, у меня теперь есть этот код для PlayerCardImages:
public ObservableCollection<ImageSource> PlayerCardImages
{
get
{
var results = new ObservableCollection<ImageSource>();
//if (PlayerCards.Count == 0)
// return results;
//else
//{
// results.Add(new BitmapImage(new Uri(@"Images" + "diamond-1.png", UriKind.Relative)));
//}
foreach (var card in PlayerCards)
{
results.Add(new BitmapImage(new Uri(@"Images" + GetCardFileName(card), UriKind.Relative)));
}
return results;
}
я использовал точный XAML, который он предложил. Это почти работает. Я говорю "почти", потому что я заметил странное поведение, при котором иногда показывалась 1 карта, а иногда нет (я никогда не получал 2 карты). Все получение карт из файлов и привязки, похоже, работает, и я отследил то, что я думаю, является ключом к последней оставшейся ошибке (и это странно). Если в отладчике я изучаю результаты и далее открываю результаты[0] в отладчике, я получаю эту карту! Мне действительно нужно открыть [0] (вы видите информацию о высоте, ширине и т. д.) чтобы это сработало. Кроме того, если я откройте [1], вместо этого я получу эту карту. Почему открытие информации об отладчике будет иметь какой-либо эффект? Для тех из вас, кто может спросить: что случится, если вы откроете обе карты в отладчике... это не работает. Я получаю исключение тайм-аута операции. Я скажу, что, возможно, мои файлы изображений большие. 10Kbytes до 30 Kbytes. В этом проблема? Я предполагаю, что нет, и что это тонкая проблема с чтением изображений или привязки. Что происходит? Спасибо, Дэйв
2 ответов
во-первых, вы не должны использовать элементы управления изображением в ViewModel. У вас уже есть элемент управления Image в DateTemplate вашего представления. Вы хотите связать Source
свойство этого изображения conntrol, и свойство источника этой привязки не может быть другим изображением.
вместо этого ваш ViewModel будет либо использовать ImageSource
(или производный класс, например BitmapImage
) как тип изображения, как это:
public ObservableCollection<ImageSource> PlayerCardImages
{
get
{
var results = new ObservableCollection<ImageSource>();
foreach (var card in PlayerCards)
{
results.Add(new BitmapImage(new Uri(card.ImageUrl)));
}
return results;
}
}
или просто URIs изображения или пути, как существует автоматическое преобразование из string
to ImageSource
встроенный в WPF:
public ObservableCollection<string> PlayerCardImages
{
get
{
var results = new ObservableCollection<string>();
foreach (var card in PlayerCards)
{
results.Add(card.ImageUrl);
}
return results;
}
}
теперь вы свяжетеItemsSource
свойства PlayerCardGames
коллекция, и в DataTemplate вы привязываете непосредственно к элементу коллекции. DataContext ListView должен быть установлен в экземпляр объекта, который определяет PlayerCardGames
собственность.
<ListView ItemsSource="{Binding PlayerCardGames}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Source="{Binding}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
UPDATE: поскольку возникает проблема с загрузкой файлов изображений, вы можете попробовать следующее метод. Он загружает изображения синхронно, и вы можете пройти через отладчик.
public static ImageSource LoadImage(string fileName)
{
var image = new BitmapImage();
using (var stream = new FileStream(fileName, FileMode.Open))
{
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = stream;
image.EndInit();
}
return image;
}
вы можете использовать этот метод в вашей PlayerCardGames
свойство getter, как это:
foreach (var card in PlayerCards)
{
results.Add(LoadImage(@"Images\" + GetCardFileName(card)));
}
Я действительно не пытался воспроизвести вашу проблему, но я буду, если это не решит ее:
в вашем первом блоке xaml я думаю, что вы перепутали привязки. Это было бы так, как я ожидаю, ItemsSource для ObservableCollection изображений, Источник Изображения для изображения.
<Image Source="{Binding}" ... />
<ListView Name="lvwTitles" ItemsSource="{Binding PlayerCardImages}" ... />
во втором блоке Вы вообще опустили исходную привязку:
<Image Source="{Binding}" Height="50" Width="40" />