[英]Displaying Images in ListView (or something better!) in WPF MVVM using databinding
我正在尝试在ListView中显示一些图像,但没有成功。 我正在使用WPF MVVM,并且ListView是简单显示西装和排名数据的保留。 (请参阅我以前的文章: WPF中的MVVM-如何向ViewModel发出Model更改的警报...或者如果有兴趣,我应该这样做吗? )也就是说,我可以使用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但是,它似乎并没有进行数据绑定,正如我未击中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>
这段代码肯定经过了数据绑定-在程序的开始以及每当项目添加到集合中时,我的断点都会被击中。 但是没有图像显示。 而不是用更多无法使用的XAML折磨您,也许我可以要求某人向我指出一些代码/示例/文档,这些代码/示例/文档显示了如何将图像列表绑定到ListView(如果您确实认为ListView是不当)。 请注意,我的收藏是我要绑定的东西。 我注意到,在许多示例中,它们都绑定到子属性。 也就是说,他们可能有一个相册集合,并且对于每个相册,它们都绑定到其属性图像(请参阅: 在WPF ListView中将项目显示为图像 )。
任何想法或帮助将不胜感激。
-戴夫
附加信息。
根据Clemens的建议,我现在有了用于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张卡)。 从文件和绑定中获取的所有卡似乎都在工作,我追踪了我认为是最后一个bug的关键的原因(这是BIZARRE)。 如果在调试器中检查结果,然后在调试器中进一步打开结果[0],则显示该卡! 实际上,我必须打开[0](您会看到有关高度,宽度等的信息)才能正常工作。 此外,如果我打开[1],则会显示该卡。 为什么打开调试器信息会有影响? 对于那些可能会问的人,如果在调试器中打开两张卡,那会发生什么……那是行不通的。 我收到操作超时异常。 我会说也许我的图像文件很大。 10 KB到30 KB。 那是问题吗? 我猜不是,那是阅读图像或装订的一个微妙问题。 到底是怎么回事? 谢谢戴夫
首先,您不应在ViewModel中使用Image控件。 您的视图的DateTemplate中已经有一个Image控件。 您想绑定此Image conntrol的Source
属性,并且此绑定的source属性不能是另一个Image。
相反,您的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;
}
}
或者只是图像URI或路径,因为WPF中内置了从string
到ImageSource
的自动转换:
public ObservableCollection<string> PlayerCardImages
{
get
{
var results = new ObservableCollection<string>();
foreach (var card in PlayerCards)
{
results.Add(card.ImageUrl);
}
return results;
}
}
现在,您可以将Listbox的ItemsSource
属性绑定到PlayerCardGames
集合,然后在DataTemplate中直接绑定到该集合项。 ListView的DataContext必须设置为定义PlayerCardGames
属性的对象的实例。
<ListView ItemsSource="{Binding PlayerCardGames}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Source="{Binding}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
更新:由于加载图像文件似乎存在问题,您可以尝试以下方法。 它同步加载图像,您可以逐步调试。
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
属性获取器中使用此方法,如下所示:
foreach (var card in PlayerCards)
{
results.Add(LoadImage(@"Images\\" + GetCardFileName(card)));
}
我并没有真正尝试重现您的问题,但是如果这不能解决问题,我会:
在您的第一个xaml块中,我认为您混合了绑定。 这就是我所期望的,ItemsSource到Images的ObservableCollection,Image Source到Image。
<Image Source="{Binding}" ... />
<ListView Name="lvwTitles" ItemsSource="{Binding PlayerCardImages}" ... />
在第二个块中,您完全省略了Source绑定:
<Image Source="{Binding}" Height="50" Width="40" />
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.