populate listview dynamically - wpf

If i bind a data table to WPF Toolkit-data-grid.....no need to specify the column names there...it will automatically take that from the datable.
But if I am binding a list-view to an observable collection...I have to specify the column header names for each column one by one..in xaml file.
So if I have a list of column names ->List<ColumnHeaderNames>
along with
list of item to populate ->List<Object to populate list>
I can bind item list to list-view...and column name list to list-view header...but i don't know if there s any property in list-view...to bind my header.
That means...
I have a user control in which i have 2 list-views ...one is available and another is selected. I need this user control shud be reusable...That means...if I am binding a list like ...the list shud contain two columns...first column with name as "state" and second column name as "county". But if I am binding a list like ..Then listview shud contain 3 columns...with column names as fruit, color and price.

I think the best for you would be to set the View property of your ListView to a GridView. Then you can easily bind the columns header :
<ListView ItemsSource="{Binding ListOfValues}">
<ListView.View>
<GridView >
<GridViewColumn DisplayMemberBinding="{Binding XVal}" Header={binding header}"/>
</GridView>
</ListView.View>
</ListView>
for more information you can go there http://msdn.microsoft.com/en-us/library/system.windows.controls.gridview.aspx

And if you use a struct which contains the list and the name : < {listOfFruits,"Fruits"}, {listofStates,"States>
And then :
<ItemsControl ItemsSource="{Binding ListOfStruct}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ListView ItemsSource="{Binding ListOfitem}">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding}" Header="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}, Path=DataContext.Header}"/>
</GridView>
</ListView.View>
</ListView>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
It is not the best way but I don't know how to do

Related

which wpf control should I use in case i need only 2 columns?

which wpf control Should i use in case I need only two columns. the first colum contains Property name and second column contains its value. however, on the top of all those properties I need a header of each columns like PROPERTY and VALUE. I know datagrid would not be a good solution for this. can someone suggest me which control to use or should I stick to Grid and set those header manually.
If you really can't use a DataGrid, then the GridView is probably your best bet... and when I say best, I mean easiest really. Assuming that you have a collection of your data type named Items and that the data type inside the collection has two properties, Property and Value, you could use this:
<ListView ItemsSource="{Binding Items}" HorizontalAlignment="Center"
VerticalAlignment="Center">
<ListView.View>
<GridView>
<GridViewColumn Header="Property" DisplayMemberBinding="{Binding Property}" />
<GridViewColumn Header="Value" DisplayMemberBinding="{Binding Value}"/>
</GridView>
</ListView.View>
</ListView>

Is it possible to add multiple, column-aligned controls as ListViewItems within XAML?

I have a ListView in which I need to add a fixed amount of items to in the XAML. (I don't need to dynamically add items to the list and I want to handle data binding from within the xaml as well.)
I understand how to add text as ListViewItems simply with <ListViewItem content="blah"/>
What I want to do is something like:
<ListViewItem><TextBox/><Label/></ListViewItem>
where the TextBox is appointed to the first column in my listview and the label to the second.
Is this at all possible to do within the XAML only? No code-behind. Would it be doable with a datagrid?
If you only need one row in your ListView, with multiple columns, you can change the ItemsPanel to a StackPanel with horizontal Orientation
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
If you need more than one row in your ListView, you can still place more than one element (horizontally) in a row by using a stackpanel as your ListViewItem, and placing children controls in it.
<ListView>
<ListViewItem>
<StackPanel Orientation="Horizontal">
<TextBox></TextBox>
<Label></Label>
</StackPanel>
</ListViewItem>
</ListView>
Edit:
To have a column with a certain type of control, you can assign a CellTemplate to a GridView's Column.
<ListView>
<ListView.View>
<GridView>
<GridViewColumn Header="TextBoxColumn">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding Anything}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
However, you would still need to populate the gridview from codebehind.

DataTemplating for data binding of nested ObservableCollections

I am attempting to create a ListView control which is populated via a binding to an ObservableCollection, which itself contains another ObservableCollection from which I need to display data in the ListView.
To clarify I have an object hierarchy as follows:
ClassA
{
int ID = 123;
string Name = "Value";
}
ClassB
{
int ID = 456;
ObservableCollection<ClassA> CollectionOfClassA;
}
ClassC
{
int ID = 789;
ObservableCollection<ClassB> CollectionOfClassB;
}
From this I would like to end up with the following ListView layout:
(ClassC.CollectionOfClassB ListView)
+-------------+-------------+------------------+--------------------------------+
| ClassB.ID | CollectionOfClassA.ClassA.ID | CollectionOfClassA.ClassA.ID |
+-------------+-------------+------------------+--------------------------------+
| ClassB.ID | CollectionOfClassA.ClassA.ID | CollectionOfClassA.ClassA.ID |
+-------------+-------------+------------------+--------------------------------+
To achieve this I would assume I need to bind my ListView to my CollectionOfClassB collection, however, the datatemplate structure and subsequent binding for producing the rows has me a bit stumped.
Can anyone assist me with this please?
Many thanks,
Edit:
The first column in the table above references the ID field for the indexed object in the ClassC.CollectionOfClassB collection, each row being an individual object stored in the CollectionOfClassB.
Each of the ClassB objects stored in CollectionOfClassB has its own CollectionOfClassA, which I am attempting to place in the listview on the same row as its parent. Each ClassA object in CollectionOfClassA being a column.
Edit 2:
The first column is populated by the ID field from ClassB for the current item in the CollectionOfClassB, the subsequent columns are populated with data from each item in the CollectionOfClassA. The column header would be ClassA.ID, whilst the content would be ClassA.Name for example.
I am looking for example XAML markup that will allow me to achieve this.
If you know that ClassB.CollectionOfClassA is always the same length, you can bind to an indexed value of it
Here's a rough example
<!-- Assumes DataContext is ClassC -->
<ListView ItemsSource="{Binding CollectionOfClassB}">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Id}" Header="ClassB.Id" />
<GridViewColumn DisplayMemberBinding="{Binding CollectionOfClassA[0].Id}" Header="ClassA[0].Id" />
<GridViewColumn DisplayMemberBinding="{Binding CollectionOfClassA[1].Id}" Header="ClassA[1].Id" />
</GridView>
</ListView.View>
</ListView>
If you have a dynamic number of columns, it becomes a bit trickier
The simplest way would be to use a custom column and display the items in something like a horizontal StackPanel
<!-- Assumes DataContext is ClassC -->
<ListView ItemsSource="{Binding CollectionOfClassB}">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Id}" Header="ClassB.Id" />
<GridViewColumn Header="CollectionOfA"
<GridViewColumn.CellTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding CollectionOfClassA}">
<ItemsControl.ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsControl.ItemsPanelTemplate>
<ItemsControl.ItemTemplate>
<TextBlock Text="{Binding Id}" Width="50" />
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridView>
</ListView.View>
</ListView>
Of course, this doesn't use the built-in GridView features like sorting

Get GridViewColumn from control inside DataTemplate

Example:
<ListView Name="lvAnyList" ItemsSource="{Binding}">
<ListView.View>
<GridView>
<GridViewColumn Header="xx" DisplayMemberBinding="{Binding XX}" CellTemplate="{DynamicResource MyDataTemplate}"/>
<GridViewColumn Header="yy">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding YY}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
If I access the TextBlock inside DataTemplate I will have access to information about the bound path.
But I don't know how to find (starting from the TextBlock) its containing GridViewColumn (which is in the GridViewRowPresenter columns list) and compare it to the grid's GridViewColumn (from GridViewHeaderRowPresenter column list) to get the header's name.
At the end I should have the pairs: xx->XX, yy->YY
I can find a list of all TextBlocks inside ListView by using this:
GridViewRowPresenter gvrp = ControlAux.GetVisualDescendants<GridViewRowPresenter>(element).FirstOrDefault();
IEnumerable<TextBlock> entb = GetVisualDescendants<TextBlock>(gvrp);
I can find a list of all GridViewColumnHeaders:
GridViewHeaderRowPresenter gvhrp = ControlAux.GetVisualDescendants<GridViewHeaderRowPresenter>(element).FirstOrDefault();
And I cannot find the connection between the TextBlocks and the GridViewColumns...
I hope this is understandable.
GridViewColumns are abstract objects they never appear anywhere in the UI, you can try to name the column and bind it to the Tag of a control where you need it using ElementName or if that fails a Source with x:Reference on the name.

How to bind to ColumnCollection for a GridView using XAML

I have a collection of objects which I would like to represent columns in a GridView.
Currently I am binding individual columns in my GridView to items in the collection like this:
<ListView>
<ListView.View>
<GridView>
<GridViewColumn Header="{Binding Path=MyColumns[0].Title}"></GridViewColumn>
<GridViewColumn Header="{Binding Path=MyColumns[1].Title}"></GridViewColumn>
<GridViewColumn Header="{Binding Path=MyColumns[2].Title}"></GridViewColumn>
</GridView>
</ListView.View>
</ListView>
This works well, but what I really want to do is to bind to the collection itself (since the number of items in the collection might change at run-time). I would like to accomplish this in XAML. What I have in mind is something like this (note this does not work - the ColumnsSource attribute is make-believe):
<ListView>
<ListView.View>
<GridView ColumnsSource="{Binding Path=MyColumns}">
</GridView>
</ListView.View>
</ListView>
Can this be done? If so, how?
You can use an attached property to create a ColumnsSource property, see this question for an example.

Resources