WPF LIstView Binding to Column Headers - c#

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}

Related

ListView doesn't see binding object properties

I have a trouble with displaying properties of instance of external class. There is ListView markup:
<ListView
x:Name="transportListView"
SelectionMode="None"
ItemsSource="{Binding MyModel}">
<ListView.ItemTemplate>
<DataTemplate>
<Border Padding="15" HorizontalAlignment="Center" Margin="0,0,0,10" Background="Gray">
<StackPanel Margin="0,0,0,0">
<TextBlock
Text="{Binding ItemName}"
Margin="0,0,0,0"/>
<TextBlock
Text="{Binding ItemCount}"
Margin="0,0,0,0"/>
</StackPanel>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
MyModel is the page property:
...
public ObservableCollection<ExternalClass> MyModel { get; set; }
...
ExternalClass is the class in some referenced library:
namespace Library.Entities
{
public class ExternalClass
{
public string ItemName { get; set; }
public int ItemCount { get; set; }
}
}
So when I run my application I see list items because I set grey color, but ItemName and ItemCount is not displaying, why? I adding items to collection correctly and binding works for internal classes perfectly.
Change your ListView's ItemsSource to ItemsSource="{Binding}". Like this:
<ListView x:Name="transportListView" ItemsSource="{Binding}">
....
Also in the code behind add this.DataContext = MyModel; below the InitializeComponent();:
public Window1()
{
InitializeComponent();
this.DataContext = MyModel;
}
To Use ListView you also need to Define View (GridView) for it:
<ListView ItemsSource="{Binding MyModel}">
<ListView.View>
<GridView>
<GridViewColumn Width="140" Header="Name" DisplayMemberBinding="{Binding ItemName}"/>
<GridViewColumn Width="140" Header="Count" DisplayMemberBinding="{Binding ItemCount}" />
</GridView>
</ListView.View>
</ListView>
If you want to define template for each row then you can use a ListBox instead of ListView:
<ListBox ItemsSource="{Binding MyModel}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border Padding="15" HorizontalAlignment="Center" Margin="0,0,0,10" Background="Gray">
<StackPanel Margin="0,0,0,0">
<TextBlock Text="{Binding ItemName}" Margin="0,0,0,0"/>
<TextBlock Text="{Binding ItemCount}" Margin="0,0,0,0"/>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

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.

How to access a property path of each object in ItemsSource of a ListView from a DataTemplate

How can I access a property path of each object in ItemsSource of a ListView from a DataTemplate?
I'm trying something like
public class Person : INotifyPropertyChanged
{
private string _name;
public string Name
{
get {return _name;}
set
{
_name = value;
OnPropertyChanged();
}
}
}
public partial class MyControl : UserControl, INotifyPropertyChanged
{
private ObservableCollection<Person> _persons;
public ObservableCollection<Person> Persons
{
get {return _persons;}
set
{
_persons = value;
OnPropertyChanged();
}
}
}
<!-- MyControl.xaml.cs -->
<Grid DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}">
<ListView ItemsSource="{Binding Persons}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name1" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="Name2">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext}"
Text="{Binding Name}" TextAlignMent="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
In MyControl.xaml.cs, When I use DisplayMemberBinding in a GridViewColumn of a ListView,
the Name Property of each Person object in the ItemsSource Persons can be directly bound as in Name1.
But when I set a DataTemplate to a GridViewColumn in order, for example, to manually set TextAlignMent as in Name2,
it is impossible to directly access the Name Property of each Person object in the ItemsSource Persons.
I resolved this problem by using TemplatedParent as shown in the code above.
Although this code normally works and I can get what I'm aiming to,
the VisualStudio warns me with the message "Can't resolve the symbol" in the part of Text="{Binding Name}".
Is there a simpler and more appropriate way to realize this kind of DataBinding?
You just bind to the Name property
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" TextAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
And you don't need to do this:
<Grid DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}">
The DataContext is accesible to the entire tree.
If you're not using MVVM you can set the datacontext in code behind:
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
...
If you get this to work, errors and warnings in Output Window are just false positives

Binding ListView

I have a ListView with the following code:
<ListView Name="ListView1">
<ListView.View>
<GridView>
<GridViewColumn Header="File" Width="60">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Width="28" Height="28" Source="{Binding Icon}" Name="img"/>
<TextBlock HorizontalAlignment="Right" VerticalAlignment="Center" Text="{Binding File}"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Type" Width="70" DisplayMemberBinding="{Binding Type}"/>
<GridViewColumn Header="Password" Width="150">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Width="145" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Can someone tell me how can I add items in it during run time and set all the bindings (Icon,File,Type)?
You create a class like:
class MyData
{
public string File { get; set; }
public string Icon { get; set; } // a path to an Icon
...
}
and then you use (in for example Window_Loaded) an
ObservableCollection<MyData> data = new ObservableCollection<MyData>();
listView1.Items = data;
data.Add(new MyData { File="text", ... });

How to display values as images in GridViewColumn?

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;

Categories

Resources