How to display values as images in GridViewColumn? - c#

I have a GridViewColumn which I have bound as so:
<GridViewColumn Header="Validated" DisplayMemberBinding="{Binding Path=Validated, Converter={StaticResource imageConverter}}" />
The Binding Path = Validated returns an Enumerated value, the imageConverter takes that value and returns a System.Windows.Media.Imaging.BitmapImage. I have checked the value of the object referenced when one of these BitmapImage objects is created, and it appears to contain an image of the correct size.
My problem now is that what is being displayed in the GridView is the URI of the BitmapImage (as text), and not the image itself.
What am I doing wrong this time?

Change imageConverter to return the uri of the image instead of an actual image.
<GridViewColumn Header="Validated">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding Path=Validated, Converter={StaticResource imageConverter}}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>

Taken from this website:
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/96f18c2b-cade-42d9-b544-c64a7ce3d82b
First you should have a class that contains image information, at least its address.
public class VideoGame
{
public string Name
{
get;
set;
}
public string Image
{
get;
set;
}
}
Second, add some instances into one ObservableCollection.
public partial class Window1 : Window
{
private ObservableCollection<VideoGame> _games =
new ObservableCollection<VideoGame>();
public ObservableCollection<VideoGame> Games
{
get { return _games; }
}
public Window1()
{
_games.Add(new VideoGame() {
Name = "Crysis",
Image = #"C:\Crysis_Boxart_Final.jpg" });
_games.Add(new VideoGame() {
Name = "Unreal Tournament 3",
Image = #"C:\Gearsofwar.JPG" });
_games.Add(new VideoGame() {
Name = "Gears of War",
Image = #"C:\Crysis_Boxart_Final.jpg" });
InitializeComponent();
}
}
Third, set the DataTemplate of GridViewColumn.CellTemplate.
<Window x:Class="VerticalAlignSnippet.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="512" Width="512" Name="myWindow">
<Grid>
<ListView Name="myListView"
ItemsSource="{Binding ElementName=myWindow, Path=Games}">
<ListView.View>
<GridView>
<GridViewColumn Header="Title" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="Image">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<Image Source="{Binding Image}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
This approach is done in XAML. You can make use of XamlReader to load this DataTemplate in the code behind.
string str = "<DataTemplate xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"><Grid><Image Source=\"{x:Null}\" /></Grid></DataTemplate>";
DataTemplate template = new DataTemplate();
template = XamlReader.Parse(str) as DataTemplate;
.....
gv1.Columns[3].CellTemplate = template;

Related

How to display a folder of shortcuts into a DataGrid or another control using WPF/c#

I have a folder (X:\Shortcuts) with shortcuts which could have the following extensions
LNK, URL, EXE
I want to show a grid of the shortcuts (Name and Icon) so the user can select them and they will get copied to H:\Desktop if it exists otherwise %USERPROFILE%\Desktop
I don't need help with copying the file. I need help with displaying the contents of a folder as a Grid in my WPF application
Someone referred me to http://www.wpfsharp.com/2012/10/23/displaying-images-from-a-folder-with-details-in-wpf/
but this assumes the folder is filled with images.
My Code-behind code
private ObservableCollection<Shortcut> shortcutItems;
public ObservableCollection<Shortcut> ShortcutItems
{
get { return shortcutItems; }
set { shortcutItems = value; }
}
private ObservableCollection<Shortcut> GetIcons()
{
if (shortcutItems == null)
shortcutItems = new ObservableCollection<Shortcut>();
shortcutItems.Clear();
foreach (var item in Directory.GetFiles(path).Where(x => x.EndsWith(".lnk")))
{
var icc = Icon.ExtractAssociatedIcon(item);
shortcutItems.Add(new Shortcut()
{
Name = System.IO.Path.GetFileName(item.Substring(0, item.Length - 4)),
BitMapIcon = System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(icc.Handle,
System.Windows.Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions())
});
}
return shortcutItems;
}
private void getShortCuts()
{
shortcutItems = GetIcons();
}
My Entire XAML
<UserControl x:Class="Camden_Automated_Help_Desk.AvailableShortcuts"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Camden_Automated_Help_Desk"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<DataGrid ItemsSource="{Binding ShortcutItems}" AutoGenerateColumns="False" >
<DataGrid.Columns>
<DataGridTemplateColumn Header="Icons">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding BitMapIcom}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
</DataGrid.Columns>
</DataGrid>
<Button x:Name="buttonCopy" Content="Copy Shortcuts" HorizontalAlignment="Left" Margin="165,265,0,0" VerticalAlignment="Top" Width="125" FontSize="16"/>
<Button x:Name="buttonReset" Content="Refresh" HorizontalAlignment="Left" Margin="10,265,0,0" VerticalAlignment="Top" Width="125" FontSize="16" Click="buttonReset_Click"/>
</Grid>
</UserControl>
I see the header showing the word Icon and label Name but I don't see the Icons or the Name of the Icons in the DataGrid
you need to extract the icons from the shortcut/file.
I made the following Shortcut class that has a name property and a bitmap(image) property.
public class Shortcut
{
public Shortcut()
{
}
public string Name { get; set; }
public BitmapSource BitMapIcom { get; set; }
}
In my MainViewModel declared an ObservableCollection of Shortcuts called ShortcutItems and use the following method to populate the collection with 'items' from a folder.
private ObservableCollection<Shortcut> shortcutItems;
public ObservableCollection<Shortcut> ShortcutItems
{
get { return shortcutItems; }
set { shortcutItems = value; }
}
private ObservableCollection<Shortcut> GetIcons()
{
if (shortcutItems == null)
shortcutItems = new ObservableCollection<Shortcut>();
shortcutItems.Clear();
foreach (var item in Directory.GetFiles(#"C:\Users\albErt\Desktop").Where(x => x.EndsWith(".lnk")))
{
var icc = Icon.ExtractAssociatedIcon(item);
shortcutItems.Add(new Shortcut()
{
Name = System.IO.Path.GetFileName(item.Substring(0, item.Length - 4)),
BitMapIcom = System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(icc.Handle,
System.Windows.Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions())
});
}
return shortcutItems;
}
And in the viewmodel constructor just ShortcutItems = GetIcons();
Make sure your directory path is correct.
It loops through all the files that have the extension ".lnk"(shortcuts). Extracts the icon from the path and converts it to a bitmap. It's not perfect but it retrieves the icons.
I used a DataGrid to test if the icons are displayed. If you use a datagrid just add the ObservableCollection as the Itemssource and create a templatecolumn for the image:
This datagrid is only thing in my XAML, other than this I set the datacontext behind code.
<DataGrid ItemsSource="{Binding ShortcutItems}" AutoGenerateColumns="False" >
<DataGrid.Columns>
<DataGridTemplateColumn Header="Icons">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding BitMapIcom}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
</DataGrid.Columns>
This is how using listview would be :
<ListView ItemsSource="{Binding ShortcutItems}" >
<ListView.View>
<GridView>
<GridViewColumn Header="Icon">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding BitMapIcom}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
</GridView>
</ListView.View>
</ListView>

How do I get the SelectedItem in a Listview with Listbox in it?

I am having trouble getting the selecteditem from a listbox which is a child of a listview. Everything that I've tried returns the GpoObject which is set at the parent listview, but not the selected OuLink from the Listbox.
This is my DataTemplate for the ListBox:
<DataTemplate x:Key="OuTemplate">
<Label Content="{Binding Path=Path}"/>
</DataTemplate>
This is my Listview with the ListBox in it:
<ListView x:Name="OutListView"
BorderBrush="#FFA0A0A0"
BorderThickness="1">
<ListView.View>
<GridView>
<GridViewColumn Header="Group Policy Objects"
Width="Auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Grid.Column="0"
Text="{Binding Path=Name}"
Width="Auto"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Organizational Units">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ListBox Grid.Column="1"
ItemsSource="{Binding Path=OUs}"
ItemTemplate="{DynamicResource OuTemplate}"
Width="Auto" Height="Auto"
BorderThickness="0"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Object for binding:
public class GpoObject
{
public string Name {get; set;}
public string Id { get; set; }
public List<OuLink> OUs { get; set; }
}
public class OuLink
{
public string Path { get; set; }
}
Here are two ways to access the Path off of the ListBox selected item. I have named the listbox to make it easier in Xaml. To show the selected info I pathed to it in a textbox now which resides above the Listbox (see image):
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock x:Name="tbSelected"
Text="{Binding ElementName=PathBox, Path=SelectedItem.Path}" />
<ListBox x:Name="PathBox"
SelectionChanged="PathBox_OnSelectionChanged"
ItemsSource="{Binding Path=OUs}"
ItemTemplate="{DynamicResource OuTemplate}"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
Then on when the selection changes I present the user with a message box of the selected path:
private void PathBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var lbi = sender as ListBox;
if (lbi != null)
if (lbi.SelectedItem != null)
{
var link = lbi.SelectedItem as OuLink;
if (link != null)
MessageBox.Show(link.Path);
}
}
Here is a selection and its propagation to the textbox and the message box:
I suggest that within the OnSelectionChanged instead of a messagebox you place that selection into a INotifyPropertyChanged string property on your ViewModel and propagate it that way to other items within the program.
Add SelectedItem="{Binding SelectedOuLink}" to your ListBox in your xaml.
Then in your GpoObject class add:
public OuLink SelectedOuLink { get; set; }
You can now retrieve the selected OuLink object via SelectedOuLink.

c# WPF CellTemplate / DataTemplate for an Image list / array

What I have:
my class:
public class MyImage
{
public String ImagePath { get; private set; }
public String Name { get; private set; }
// ...
}
XAML:
<Window.Resources>
<DataTemplate x:Key="template_image">
<Image Source="{Binding Path=ImagePath}" Stretch="None" />
</DataTemplate>
<DataTemplate x:Key="template_name">
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</Window.Resources>
<ListView x:Name="gui_listview_graphics" Margin="75,0,0,0">
<ListView.View>
<GridView>
<GridViewColumn Header="Graphic" CellTemplate="{StaticResource template_image}" />
<GridViewColumn Header="Name" CellTemplate="{StaticResource template_name}" />
</GridView>
</ListView.View>
</ListView>
Works fine.
Now what i now want..
I need to display an Image-List instead of just one Image.
my new class:
public class MyNewImage
{
public ObservableCollection<String> ImagePath { get; private set; }
public String Name { get; private set; }
// ...
}
The DataTemplate should contain an Stackpanel which contains all images..
Is it possible?
If yes, how ..
Thank you!
In your DataTemplate include an ItemsControl whose Items property is bound to your collection of image paths. Your ItemTemplate for the ItemsControl will essentially be the same as your current DateTemplate, except you will use an implicit Binding for the Image source, since the string itself is your object. The default template for the ItemsPanel for an ItemsControl is a StackPanel already, but you can change this if necessary by setting the ItemsPanel property.
This template should work:
<DataTemplate x:Key="template_image_list">
<ItemsControl ItemsSource="{Binding ImagePath}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"></Image>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
Because a StackPanel does not have a property ItemsSource, you cannot bind directly to it. If you use it as ItemsPanelTemplate of an ItemsControl everything is fine.

Unable to Bind ObservableCollection from MVVM to ListView in WPF

I am trying to bind the List View to Observable Collection of a class and for some reason, the DisplayMemberBinding attribute of GridViewColumn is not binding to the content of collection.
If I use ListView.ItemTemplate, everything works fine. But I need the data in the form of a grid, so I am using GridView inside ListView.View.
First Image, Image 1 is the AssessmentSummaryList content in debug mode.
Second Image, Image 2 is the final output shown on the screen. The content from the list is not binding to the GridViewColumn.
These are the two view models I am using:
public class AssessmentSummaryViewModel : BaseViewModel
{
public string Question { get; set; }
public string Title { get; set; }
public string SelectedOption { get; set; }
public int Id { get; set; }
}
public class AssessmentViewModel : BaseViewModel
{
private ObservableCollection<AssessmentSummaryViewModel> assessmentSummaryList;
public ObservableCollection<AssessmentSummaryViewModel> AssessmentSummaryList
{
get { return assessmentSummaryList; }
set
{
assessmentSummaryList = value;
NotifyPropertyChanged("AssessmentSummaryList");
}
}
public void SetNextAssessment()
{
AssessmentSummaryList= Service.GetAssessmentSummary(ApplicationModel.SelectedModule.Id,
ApplicationModel.SelectedUtility.Id); //the service returns ObservableCollection<AssessmentSummaryViewModel> data
var EndScreen = new AssessmentSummaryView(); //Setting the last screen to AssessmentSumamryView, this will be called dynamically from other UserControl Xaml Page
}
}
AssessmentSummaryView Xaml Code is as follows:
<ListView x:Name="lstvSummary1" Grid.Row="2" ItemsSource="{Binding Path=DataContext.AssessmentSummaryList, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">
<ListView.View>
<GridView ColumnHeaderContainerStyle="{StaticResource myHeaderStyle}">
<GridViewColumn DisplayMemberBinding="{Binding Path=Title}" Width="200">
<GridViewColumnHeader Content="Design Element" />
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Path=Question}" Width="400">
<GridViewColumnHeader Content="Question" />
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Path=SelectedOption}" Width="300">
<GridViewColumnHeader Content="Response" />
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
AssessmentSummaryView Code-behind is as follows:
public partial class AssessmentSummaryView : UserControl
{
public AssessmentSummaryView()
{
InitializeComponent();
}
}
Try something like:
<ListView ItemsSource="{Binding Path=DataContext.AssessmentSummaryList, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Design Element" Width="200" DisplayMemberBinding="{Binding Path=Title}"/>
<GridViewColumn Header="Question" Width="400" DisplayMemberBinding="{Binding Path=Question}"/>
<GridViewColumn Header="Response" Width="300" DisplayMemberBinding="{Binding Path=SelectedOption}"/>
</GridView.Columns>
</GridView>
</ListView.View>

WPF LIstView Binding to Column Headers

I'm attempting to create a listview that binds dynamically to a set of dates. So the user would b able to select a date range and the results for the chosen dates would show up with the date in the column header. I've got it all working with just one problem, the dates don't show up in the header. I've got the following which I can't see any reason why it doesn't work:
public class KPIResult : DependencyObject
{
public static readonly DependencyProperty DateProperty = DependencyProperty.Register("Date", typeof(DateTime), typeof(KPIResult), new UIPropertyMetadata(null));
public DateTime Date
{
get { return (DateTime)GetValue(DateProperty); }
set { SetValue(DateProperty, value); }
}
public static readonly DependencyProperty ResultProperty = DependencyProperty.Register("Result", typeof(int), typeof(KPIResult), new UIPropertyMetadata(null));
public int Result
{
get { return (int)GetValue(ResultProperty); }
set { SetValue(ResultProperty, value); }
}
}
And the code for the ListView:
<ListView Margin="6" ItemsSource="{Binding ElementName=This, Path=KPICollection}" Name="lvKPIView" Grid.ColumnSpan="2">
<ListView.View>
<GridView>
<GridViewColumn Width="40" >
<GridViewColumnHeader Tag="KPIResult[0]" Content="{Binding Path=KPIResults[0].Date}" />
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=KPIResults[0].Result}" />
<TextBox Text="{Binding Path=KPIResults[0].Result}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
The results are displayed just fine. Just no dates in headers :(.
Any ideas guys?
Cheers,
SumGuy
Try this way:
<ListView Margin="6" DataContext="{Binding ElementName=This}" ItemsSource="{Binding KPICollection}" Name="lvKPIView" Grid.ColumnSpan="2">
<ListView.View>
<GridView>
<GridViewColumn Width="40" >
<GridViewColumnHeader Tag="KPIResult[0]" Content="{Binding KPICollection.KPIResults[0].Date}" />
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=KPIResults[0].Result}" />
<TextBox Text="{Binding Path=KPIResults[0].Result}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Apparently, the problem is that you are trying to bind to a property without specifying binding source and without having DataContext of the control set to anything. The reason why binding inside CellTemplate work is that the data context for rows is automatically set to the corresponding list item instance, but this is not true for headers - they inherit data context from the parent control. So, if we specify DataContext for the ListView then binding that is used in the header will be have a relative path to that data context: {Binding KPICollection.KPIResults[0].Date}

Categories

Resources