I am trying to display some images in a ListView and have not been successful. I use WPF MVVM, and ListView is a break in the simple display of claims and rank data. (See My previous post: MVVM in WPF. How to warn ViewModel about changes in Model ... or should I , if you're interested!) That is, I could use something other than ListView (if this is advice), but I would still like to know how to do this with a ListView, considering it doable. My property that I am attached to is in the 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; } }
In my XAML codec, I use:
<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>
This idea was shamelessly stolen from: WPF - to bind images horizontally to a ListView However, it does not even appear in data binding, as evidenced by my breakpoint in PlayerCardImages, which is not a hit.
I also tried the following XAML with slightly better luck:
<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}"> <Setter Property="HorizontalContentAlignment" Value="Stretch" /> <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>
this code definitely goes through data binding - my breakpoint gets to the beginning of the program and whenever elements are added to the collection. But images are not displayed. Instead of trying to use more XAML, which doesn't work, maybe I could ask someone to give me code / examples / documents that show how to link the list of images to a ListView (or another control, if you really feel that the ListView is unacceptable). Please note that my collection is the material to which I attach. I notice that with many examples, they are related to subtasking. That is, they can have a collection of albums, and for each album they are attached to the image of the property (see Displaying elements as images in the WPF ListView ).
Any ideas or help would be greatly appreciated.
-Dave
Additional Information.
Based on Clemens' suggestions, I now have this code for 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; }
I used the exact XAML that he suggested. It almost works. I say "almost" because I noticed strange behavior that sometimes showed one card and sometimes not (I never had 2 cards). All the maps from the files and the bindings seem to work, and I kept track of what, in my opinion, is the key for the last remaining error (and this is BIZARRE). If in the debugger I check the results and then open the results [0] in the debugger, I get this card! I really have to open [0] (you see information about height, width, etc.) for this to work. Also, if I open [1], I get a card instead. Why does opening debugging information have any effect? For those of you who may ask what happens if you open both cards in the debugger ... this will not work. I get an exception from synchronization. I will say that perhaps my image files are large. 10 Kbytes to 30 Kbytes. This is problem? I guess not, and that this is a subtle issue with reading in images or snapping. What's happening? Thanks Dave