1

I want to show an image in my listview but i don't know how i should do this. My Guest class has the method GetGuestImage() it returns me a absolute path. When this file exists is should be loaded and when not a placeholder-image should be loaded.

How can i realize this?

<ListView x:Name="listview">
                    <ListView.View>
                        <GridView>
                            <GridViewColumn DisplayMemberBinding="{Binding GetGuestImage()}" Header="Image" />
                            <GridViewColumn DisplayMemberBinding="{Binding Vorname}" Header="Vorname" />
                            <GridViewColumn DisplayMemberBinding="{Binding Nachname}" Header="Nachname" />
                            <GridViewColumn DisplayMemberBinding="{Binding Postleitzahl}" Header="PLZ" />
                            <GridViewColumn DisplayMemberBinding="{Binding Ort}" Header="Ort" />
                            <GridViewColumn DisplayMemberBinding="{Binding Land}" Header="Land" />
                        </GridView>
                    </ListView.View>
                </ListView>
Sebastian L
  • 838
  • 9
  • 29
Mathis Hüttl
  • 127
  • 3
  • 18

3 Answers3

3

You could accomplish this with a CellTemplate and a value converter:

<ListView x:Name="listview" xmlns:local="clr-namespace:WpfApplication1">
    <ListView.Resources>
        <local:ImageConverter x:Key="ImageConverter" />
    </ListView.Resources>
    <ListView.View>
        <GridView>
            <GridViewColumn Header="Image">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <Image Source="{Binding Path=., Converter={StaticResource ImageConverter}}" />
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
            <GridViewColumn DisplayMemberBinding="{Binding Vorname}" Header="Vorname" />
            <GridViewColumn DisplayMemberBinding="{Binding Nachname}" Header="Nachname" />
            <GridViewColumn DisplayMemberBinding="{Binding Postleitzahl}" Header="PLZ" />
            <GridViewColumn DisplayMemberBinding="{Binding Ort}" Header="Ort" />
            <GridViewColumn DisplayMemberBinding="{Binding Land}" Header="Land" />
        </GridView>
    </ListView.View>
</ListView>

namespace WpfApplication1
{
    public class ImageConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            dynamic dataObject = value;
            if (dataObject != null)
            {
                string path = dataObject.GetGuestImage();
                if(System.IO.File.Exists(path))
                    return new Uri(dataObject.GetGuestImage(), UriKind.RelativeOrAbsolute);
            }

            return new Uri(@"c:\yourplaceholderimage.png", UriKind.RelativeOrAbsolute);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

You can't bind directly to the GetGuestImage() method though. Another idea may be to expose the path through a Uri property of your data object class and bind to this one. Then you don't need a converter:

<GridViewColumn Header="Image">
    <GridViewColumn.CellTemplate>
        <DataTemplate>
            <Image Source="{Binding GuestImage}" />
        </DataTemplate>
    </GridViewColumn.CellTemplate>
</GridViewColumn>

public class YourDataClass
{
    public Uri GuestImage
    {
        get { return new Uri(@"c:\picture.png", UriKind.RelativeOrAbsolute); }
    }

    //+ the other properties...
}
mm8
  • 163,881
  • 10
  • 57
  • 88
2

Use a Converter for that.

public class NullGuestImageToPlaceholderConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null || !File.Exists(value as string))
            return placeholderImage;

        return GetImage(value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

XAML:

<ListView x:Name="listview">
    <ListView.View>
        <GridView>
            <GridViewColumn DisplayMemberBinding="{Binding GuestImage, Converter={StaticResource nullGuestImageConverter}}" Header="Image" />
            <!-- your other columns -->
        </GridView>
    </ListView.View>
</ListView>

I don't have the GetGuestImage implementation or your full XAML, so that's the most I can do for now.

nullGuestImageConverter should be the x:Key of the converter, defined in your XAML's resources (like <UserControl.Resources>), and placeholderImage should be the implementation of how you retrieve said placeholder image (which I guess appears in GetGuestImage()).

In fact, I guess you could simply replace the content of the Convert method by your GetGuestImage one, but I can't know for sure.

Kilazur
  • 3,089
  • 1
  • 22
  • 48
  • ah okay thanks!!! i use the entityframework and i my itemsource is listview.ItemsSource = db.Gaeste.ToList(); can i get access to the object in the converter? – Mathis Hüttl Feb 03 '17 at 11:15
  • This is trickier, but doable. It can depend on your MVVM framework; for me, I'd use a service resolver that'd return a DbService, with which I could do whatever I want. This service would also be injected in the appropriate VMs. Or maybe simply do a static class if it's easier for you. Or even have your DB be a property of the VM, and pass it as the `ConverterParameter="{Binding Database}"` – Kilazur Feb 03 '17 at 11:20
  • Also, check the other answers, I indeed forgot to take into account the need for a cell template to be able to display images. – Kilazur Feb 03 '17 at 11:22
  • Check my answer. You could cast the value argument that gets passed to the Convert method to an "Gaeste" or whatever your type is called: Gaeste dataObject = value as Gaeste; – mm8 Feb 03 '17 at 11:24
  • @MathisHüttl when you set `Listview.ItemsSource` behind the scenes it does foreach item in source create a new item from the template and set that items 'DataContext' to the item in the list, so the 'DataContext' for the template is always the object in the list – MikeT Feb 03 '17 at 11:24
  • @Kilazur your placeholderImage should be a property on the converter so that the view can set it – MikeT Feb 03 '17 at 11:30
  • thanks guys i combined your answers and it worked perfect!! – Mathis Hüttl Feb 03 '17 at 11:43
0

First you need to bind to a property not a method second the DisplayMemberBinding only supports basic binding you need to switch to CellTemplate

<ListView x:Name="listview">
    <ListView.View>
        <GridView>
            <GridViewColumn Header="Image" >
               <GridViewColumn.CellTemplate>
                   <DataTemplate>
                       <Image Source="{Binding GuestImageProperty}" />
                   </DataTemplate>
               </GridViewColumn.CellTemplate>
            </GridViewColumn>
            <GridViewColumn DisplayMemberBinding="{Binding Vorname}" Header="Vorname" />
            <GridViewColumn DisplayMemberBinding="{Binding Nachname}" Header="Nachname" />
            <GridViewColumn DisplayMemberBinding="{Binding Postleitzahl}" Header="PLZ" />
            <GridViewColumn DisplayMemberBinding="{Binding Ort}" Header="Ort" />
            <GridViewColumn DisplayMemberBinding="{Binding Land}" Header="Land" />
        </GridView>
    </ListView.View>
</ListView>

then you can use the binding's TargetNullValue and FallbackValue properties to handle missing values

MikeT
  • 5,398
  • 3
  • 27
  • 43