I have an ObservableCollection of Team (ObservableCollection<Team>). In my Team class I have an ObservableCollection of "Actor" (ObservableCollection). Now I want display the actors in a Listview in with mvvm pattern.
Anyone have a solution? I did not found anything on google to show the actors in my Listview.
Thanks in advance.
<Window x:Class="Room.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Room.Views"
xmlns:localBind="clr-namespace:Room.ViewModels"
mc:Ignorable="d"
Title="" Height="300" Width="800">
<Window.DataContext>
<localBind:MainViewModel/>
</Window.DataContext>
<Grid>
<ListView Margin="10" ItemsSource="{Binding Teams}"
SelectedItem="{Binding SelectedActor}" >
<ListView.View>
<GridView>
<GridViewColumn Header="Id" Width="80" DisplayMemberBinding="{Binding Id}"/>
<GridViewColumn Header="Niggname" Width="160"
DisplayMemberBinding="{Binding Name}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
From this other stackoverflow post:
If the list is nested, you have a tree, for which you can use a
HierarchicalDataTemplate and display in a TreeView or nested
ListViews.
If you want to view in a flat list, have your ViewModel flatten the
tree, assuming you are using an MVVM pattern.
Your listview is showing each individual Team as an item. Because you have nested collections (Teams is a collection of collections of Actors), your Id and Name bindings aren't binding to the Actor items but to the Team items.
My initial solution was to go deeper and put a listview inside of a listview
<ListView ItemsSource="{Binding Teams}">
<ListView.ItemTemplate>
<DataTemplate>
<ListView Margin="10" ItemsSource="{Binding Actors}"
SelectedItem="{Binding SelectedActor}" >
<ListView.View>
<GridView>
<GridViewColumn Header="Id" Width="80" DisplayMemberBinding="{Binding Id}"/>
<GridViewColumn Header="Name" Width="160"
DisplayMemberBinding="{Binding Name}" />
</GridView>
</ListView.View>
</ListView>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
with the following result:
However, as you can see I can only select a Team. I can select an Actor within each list but this is not what you want (under running assumption you want a single list).
What was easier for me was to flatten the tree in C#. Assuming that I have a flat list of actors (regardless of team) I can do this:
<ListView ItemsSource="{Binding AllActors}"
SelectedItem="{Binding SelectedActor}" >
<ListView.View>
<GridView>
<GridViewColumn Header="Id" Width="80" DisplayMemberBinding="{Binding Id}"/>
<GridViewColumn Header="Name" Width="160"
DisplayMemberBinding="{Binding Name}" />
</GridView>
</ListView.View>
</ListView>
with the following result:
How you decide to flatten the list is up to you. Make sure to implement INPC on the Team class as well since modifying a Team inside an ObservableCollection<Team> won't tell the collection to update the binding without INPC.
If you are strictly following MVVM, I would possibly recommend creating some Dependency Propertys in your control's code behind and flatten the list there.
My rationale is that this operation is purely cosmetic. We aren't performing business logic or changing data when we flatten the list; we are only prepping it for how we want to view it. So, we shall put the code to that in the code-behind as opposed to the VM. This is a bit more difficult though since now you have to make sure you bind correctly from VM <-> DP <-> Control as opposed to VM <-> Control.
Related
I have an application which is check the incoming Mails on the Server and refresh a List with X-Values in it. Now I want to Plot the incoming Mail count in a Live Chart. I use http://lvcharts.net for this.
I have two classes a Mail Object with the Count and a TimeStamp in it and a List Class with all Mail Objects in it.
Here is my sample(pseudo) XAMl code:
<liveCharts:BarChart Name="MailChart" Grid.Row="1" Grid.Column="0">
<liveCharts:BarChart.Series>
<liveCharts:BarSeries Title="Mails" Values= "{Binding MailCountList.Count}"></liveCharts:BarSeries>
......
......
<liveCharts:BarChart.AxisY>
<liveCharts:Axis Title="Time" Labels="{Binding MailCountList.Timestamp}">
......
The Objects are in a normal List with automatically Refesh I use MVVM.
My Question is:
How can I bind a List to a XAML Value Series ?
I have used an ObservableCollection to view the Content and a normal list to fill sort etc. the Xaml Code Looks Like:
<ListView ItemsSource="{Binding TableList}" Grid.Row="0">
<ListView.View>
<GridView>
<GridViewColumn Width="50" Header="ID" DisplayMemberBinding="{Binding ID}"/>
<GridViewColumn Width="180" Header="Name" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Width="100" Header="Group" DisplayMemberBinding="{Binding Group}"/>
<GridViewColumn Width="85" Header="Version" DisplayMemberBinding="{Binding Version}"/>
</GridView>
</ListView.View>
</ListView>
The Source of the ListView is in the ItemSource and to Display Multiple Rows I use GridViewColumn with Binding to the Object Values from the List in "DisplayMemberBinding"
We are working on a ListView (C# WPF) and we didn't found how bind a list of items in columns, with each item containing itself a list of items with the same columns.
Let's illustre this in an example :
!
We got an observable collection on objects with parameters (name, etc.) and each object contain another observable collection of objects with the sames parameters (exept they haven't a list). So we want to list it in a ListView but we can't figure how !
We do not know enough ListView to implement this structure, some advices ?
Thanks in advance
I think the best way is :
XAML :
<Window.Resources>
<DataTemplate x:Key="gridViewSecondCellTemplate1">
<StackPanel Width="100">
<TextBlock Text="{Binding Content}" FontSize="15" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="gridViewCellTemplate1">
<StackPanel Width="100">
<TextBlock Text="{Binding Title}" FontSize="15" />
<ListView ItemsSource="{Binding MySecondSource}>
<ListView.View>
<GridView>
<GridViewColumn Header="{Binding Subtitle}" CellTemplate="{StaticResource gridViewSecondCellTemplate1}"/>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
</DataTemplate>
</Window.Resources>
<ListView ItemsSource="{Binding MySource}">
<ListView.View>
<GridView>
<GridViewColumn Header="Col 1" Width="100" CellTemplate="{StaticResource gridViewCellTemplate1}"/>
</GridView>
</ListView.View>
</ListView>
I didn't try this code. Try it, and say me if it is OK.
I have 2 ObservableCollection lists, which we can call A and B, then I have a GridView that I want to bind to list A and a ComboBox INSIDE that GridView, that I want to bind to list B.
I've set the ItemsSource property of the GridView by code: gridview.ItemsSource=A (and it works!). About the ComboBox its instance it is not available by code, I suppose because its definition it is enclosed between the DataTemplate tags; so I wonder how to bind the combo to list B, either by code or by XAML.
Follows the XAML code:
<ListView Grid.Row="0" Grid.Column="1" HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="lstReplacements" VerticalAlignment="Stretch">
<ListView.View>
<GridView>
<GridViewColumn HeaderContainerStyle="{StaticResource MyHeaderStyle}" Header="Wrong text" DisplayMemberBinding="{Binding Word}"/>
<GridViewColumn HeaderContainerStyle="{StaticResource MyHeaderStyle}" Header="Replacement" Width="60" DisplayMemberBinding="{Binding Replacement}" />
<GridViewColumn HeaderContainerStyle="{StaticResource MyHeaderStyle}" Header="Type" Width="30">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{??????}" DisplayMemberPath="??????" Grid.Row="1" Grid.Column="0" Name="cmbCorrectionType" Width="75" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Thanks in advance for the support!
Chris
I assume this control is in UserControl and you have set DataContext of that UserControl to the class instance where your both collections CollectionA and CollectionB resides.
You can then bind using RelativeSource:
<ComboBox ItemsSource="{Binding DataContext.CollectionB,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=UserControl}}"/>
Also you can set DataContext of ListView to the class instance and all you need to do is change AncestorType to ListView in place of UserControl in above binding.
I'm trying to switch over to WPF from Winform and so far it's a pain.
Anyway, I am trying to get this binding thing to work using DataTemplate.
I have a class:
public class TranslatorListItem
{
public string Item { get; set; }
public string OriginalMessage { get; set; }
public string TranslatedMessage { get; set; }
public string Sector { get; set; }
}
Items are added like this:
TranslatorListItem TLI = new TranslatorListItem();
TranslatorLVI.Items.Add(TLI);
My XAML DataTemplate:
<DataTemplate x:Key="MyDataTemplate">
<Border BorderBrush="#FFA4D5E5" BorderThickness="1,1,0,0" Margin="6">
<StackPanel Margin="6,2,6,2">
<TextBox Text="{Binding}" TextWrapping="Wrap" BorderThickness="0" BorderBrush="#00000000" />
</StackPanel>
</Border>
</DataTemplate>
This is how I'm trying to bind the data but it's returning this error: "Two-way binding requires Path or XPath."
<ListView Margin="23,224,27,54" Name="TranslatorLVI" ItemsSource="{Binding}" HorizontalContentAlignment="Stretch"
ItemContainerStyle="{StaticResource MyItemContainerStyle}">
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn Header="Item" DisplayMemberBinding="{Binding Path=Item}" CellTemplate="{StaticResource MyDataTemplate}" />
<GridViewColumn Header="Original Message" Width="300" CellTemplate="{StaticResource MyDataTemplate}" />
<GridViewColumn Header="Translated Message" DisplayMemberBinding="{Binding Path=TranslatedMessage}" CellTemplate="{StaticResource MyDataTemplate}" />
<GridViewColumn Header="Sector" DisplayMemberBinding="{Binding Path=Sector}" />
</GridView>
</ListView.View>
</ListView>
I need TranslatedMessage binding to be editable. So that field wont be Read-Only.
I heard I may need to set Two-way binding, but I am not sure how to do so.
Any help is appreciated.
Thanks!
I'm trying to switch over to WPF from Winform and so far it's a pain.
No, it's not. WPF is the best UI Framework in the history of mankind. winforms (or anything else) can't even be compared with it.
Your problem is you're trying to use a winforms approach in WPF and you fail.
WPF does not support developers with a winforms mentality.
All the horrible code behind hacks you're used to from winforms are completely unneeded in WPF.
Please read Rachel's Excellent Answer (and linked blog posts) about the mindshift needed when upgrading from winforms to WPF.
As mentioned in #JasRaj's answer, you're missing a DisplayMemberBinding in this case. I tested your code and added that, like this:
<GridViewColumn Header="Original Message"
DisplayMemberBinding="{Binding OriginalMessage}"
Width="300"/>
And it worked perfectly.
After a second read to your question I realized you wanted to make one of these columns editable.
First of all I will say that while what you want can be achieved with a ListView, using a DataGrid is easier.
You need to remove the DisplayMemberBindings from the ListView in order to use a CellTemplate, and therefore you need to modify the template slightly:
<DataTemplate x:Key="MyDataTemplate">
<Border BorderBrush="#FFA4D5E5" BorderThickness="1,1,0,0" Margin="6">
<TextBox Text="{Binding TranslatedMessage}"
TextWrapping="Wrap"
BorderThickness="0"
BorderBrush="#00000000" />
</Border>
</DataTemplate>
I have placed a ListView and a DataGrid side by side so you can compare them:
Here is the XAML:
<UniformGrid Columns="2">
<ListView ItemsSource="{Binding}" HorizontalContentAlignment="Stretch">
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn Header="Item" DisplayMemberBinding="{Binding Path=Item}"/>
<GridViewColumn Header="Original Message" DisplayMemberBinding="{Binding OriginalMessage}" Width="300"/>
<GridViewColumn Header="Translated Message" CellTemplate="{StaticResource MyDataTemplate}" />
<GridViewColumn Header="Sector"/>
</GridView>
</ListView.View>
</ListView>
<DataGrid ItemsSource="{Binding}"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Item" Binding="{Binding Path=Item}" IsReadOnly="True"/>
<DataGridTextColumn Header="Original Message" Binding="{Binding OriginalMessage}" IsReadOnly="True" Width="300"/>
<DataGridTextColumn Header="Translated Message" Binding="{Binding TranslatedMessage}" />
<DataGridTextColumn Header="Sector" Binding="{Binding Sector}"/>
</DataGrid.Columns>
</DataGrid>
</UniformGrid>
Notice how the ListView requires DataTemplates in order to support edition, and is read-only by default, while the DataGrid is editable by default, does not need any special templats and requires that you add the IsReadOnly="True" to columns that are intended to be read-only.
Also, I noticed you're adding items manually to the ListView using procedural code. This is not desired in WPF. You must use an ObservableCollection<> and manipulate that collection, and let the WPF Binding engine update the UI for you.
It is recommended and desired that you Separate logic/data from UI in WPF.
If you need further clarification please let me know.
WPF Rocks.
Bind the second columns of Gridview with OriginalMessage property.
like :-
DisplayMemberBinding="{Binding Path=OriginalMessage}"
it should work.
In my opinion you dont fully use the datatemplate. you just use it to display one property;
In fact you can use a DataTemplate to display all data in thie class (TranslatorListItem);
such as this
<DataTemplate x:Key="MyDataTemplate">
<Border BorderBrush="#FFA4D5E5" BorderThickness="1,1,0,0" Margin="6">
<TextBox Text="{Binding Item}"
TextWrapping="Wrap"
BorderThickness="0"
BorderBrush="#00000000" />
<TextBox Text="{Binding TranslatedMessage}"
TextWrapping="Wrap"
BorderThickness="0"
BorderBrush="#00000000" />
( ..... follow up)
</Border>
</DataTemplate>
So your ListView can design like this:
<ListView ItemsSource="{Binding}" HorizontalContentAlignment="Stretch"
ItemTemplate="{StaticResource MyDataTemplate}">
</ListView>
My application is using Self-Tracking Entities & I get my data from a WCF Service. In my WCF service query I am using the .Include("") to load entity relationships with my query.
public List<IndividualDisability> GetIndividualDisabilities()
{
using (var context = new ADATrackingEntities())
{
return context.IndividualDisabilities.OfType<IndividualDisability>().Include("ADACode").ToList();
}
}
I'm then adding the results to an ICollectionView. I have a ListView that is bound to the ICollectionView, some of the columns in my ListView are bound to values from my entities relationship. I have a master-details setup with the current item of the listview bound to the entity object i'm editing.
<ListView Margin="0,0,10,0" MaxHeight="400" MaxWidth="300" HorizontalAlignment="Left" AlternationCount="2" ItemsSource="{Binding Path=IndividualDisabilitiesSource}" IsSynchronizedWithCurrentItem="True" SelectedItem="{Binding Path=CurrentIndividualDisability, Mode=TwoWay}" SelectionMode="Single" ItemContainerStyle="{DynamicResource ListViewItemContainerStyle}">
<ListView.View>
<GridView>
<GridViewColumn Header="Case #" Width="Auto"
DisplayMemberBinding="{Binding Individual.CaseNumberShort}" />
<GridViewColumn Header="LName" Width="Auto"
DisplayMemberBinding="{Binding Individual.LastName}" />
<GridViewColumn Header="FName" Width="Auto"
DisplayMemberBinding="{Binding Individual.FirstName}" />
<GridViewColumn Header="ADA Code" Width="Auto"
DisplayMemberBinding="{Binding ADACode.ADACodeDesc}" />
</GridView>
</ListView.View>
</ListView>
The problem is that on my edit section i'm using a combobox to change a value from the selected record and its changing the related value in my ListView to a blank value in the cell. The only way I can get it to show up again is by going back to the database and loading the data again. Is there something im missing with my combobox or listview binding??
<ComboBox Height="25" Width="200" ItemsSource="{Binding ADACodesSource}"
DisplayMemberPath="ADACodeDesc" SelectedValuePath="ADACodeID"
SelectedValue="{Binding Path=CurrentIndividualDisability.ADACodeID, Mode=TwoWay,
NotifyOnValidationError=True, ValidatesOnDataErrors=True}" />
I havent been able to get it working still with the combobox, so I settled for creating a custom control. Its an AutoComplete/ComboBox that seems to have the correct type of binding. Everything works great with this control detailed in this blog post:
http://weblogs.asp.net/dwahlin/archive/2009/07/06/creating-an-combobox-style-autocompletebox-control-in-silverlight.aspx