繁体   English   中英

使用数据绑定在WPF MVVM中的ListView(或更好的东西)中显示图像

[英]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中内置了从stringImageSource的自动转换:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM