WPF creating dynamic rows using MVVM pattern - wpf

I want to load my WPF UserControl with dynamic rows. My scenario is as follows.
1. When the UserControl gets loaded, I will populate my List<string> object with some values which I will get from a database.
2. I need to create equal number of rows in my UserControl which matches the number of items in the List<string> object. The display will look something like below
Column 1 is a Label Control and Column 2 will be a TextBlock control
Label 1: Item 1 (This is the value from the List<string> object)
Label 2: Item 2
Label 3: Item 3
I know how to create rows dynamically but my problem is how do I do this when I'm using the MVVM pattern.
Note: I'm using the MVVM toolkit from CodePlex.
Thanks,
Jithu

Set the MVVM object you have as the dataContext of your UserControl, I hope the object has a Collection property in it. Then create an ItemsControl more like below
It is not clear from your description that where is really the Label and Item comes from your ViewModel. The below code will create Rows dynamically as many as your Collection.Count.
<ItemsControl ItemsSource="{Binding YourStringCollection}" HorizontalAlignment="Left" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemsTemplate>
<DataTemplate>
<TextBlock Text="{Binding}">
</DataTemplate >
</ItemsControl. ItemsTemplate >
</ItemsControl>

Related

ItemsControl rendering slowly

I am using an ItemsControl for showing alist of items and itrs xaml is like
<ItemsControl ItemsSource="{Binding ShelfItemsCollection}" Name="shelfGridView" Margin="5" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<Stackpanel>
<Image Width="150" Height="200" Stretch="Fill" Source="{Binding CoverImage}" ></Image>
+
some other infos
</Stackpanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
The problem i am facing is i had almost 100 items in list and i am doing some filtering operations on the list based on some properties and limit the results to a lesser no ( say 20 items at a time)for doing this filtering it took a lot of time to refresh and load the list view .
This is the code i used for filtering
ICollectionView dataView = CollectionViewSource.GetDefaultView(shelfGridView.ItemsSource);
dataView.Filter = CloudFilter;
dataView.Refresh();
private bool CloudFilter(object item)
{
MyObject lib = item as MyObject;
return lib.Property !=valuetofilter;
}
Is any way to improve the perfomance or any specific reason for slow rendering ?
ItemsControl doesn't support UI virtualization out of the box. Either use ListBox or make ItemsControl UI virtualized.
You can enable UI virtualization on ItemsControl by following some steps :
Set VirtualizingStackPanel.IsVirtualizing="True" on ItemsControl.
Set ItemsPanel to be VirtualizingStackPanel.
Override ControlTemplate of ItemsControl and wrap ItemsPresenter inside ScrollViewer.
Set ScrollViewer.CanContentScroll="True" on ItemsControl.
Details for the above proposal can be found here.
Moreover, you are setting ItemsSource directly to SourceCollection i.e. ShelfItemsCollection and later filtering it by getting defualtView created underneath for that collection. Binding directly with sourceCollection will force ItemsControl(non-Virtualized ofcourse) to generate 100 containers to host your underlying objects.
Instead you should create ICollectionView with filter predicate set on it and bind ItemsSource to that instance. May be you can also create CollectionViewSource and bind with it. If you bind with filtered instance, it will generate only 20 containers (non-virtualized ItemsControl).
Ofcourse, enabling UI virtualization on ItemsControl, will generate containers for only visible UI items on GUI.

split DataTemplate in different grids using ItemTemplateSelector

I am working on WPF-XAML. My requirement is :
I need to add collection of Trunks(which consists of Border & TexBlocks) in a Tab.
there will be 2 types of such Trunks (say RSPTrunkTemplate and ASPTrunkTemplate). now I need to add collection of Trunks of type RSPTrunkTemplate in one grid. then there will be GridSplitter and then I need to add another collection of Trunks of type ASPTrunkTemplate in another grid.
I am using ItemTemplateSelector as follows :
<Grid>
<ItemsControl Name="TrunkList"
ItemsSource="{Binding RSPTrunks}"
ItemTemplateSelector="{StaticResource TrunkItemTemplateSelector}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
this TrunkItemTemplateSelector is as follows :
<Helpers:TrunkItemTemplateSelector x:Key="TrunkItemTemplateSelector"
RSPTrunkTemplate="{StaticResource RSPTrunkTemplate}"
SPTrunkTemplate="{StaticResource ASPTrunkTemplate}" />
Now, RSPTrunkTemplate should be in one grid and ASPTrunkTemplate shoulb be in another grid.
How to do this. Do I have to change my approach.?
I seek your help guys.
ItemTemplateSelector, as the name suggests, is used to specify a different template for the objects inside a ItemsControl, not to do filtering. If i understand correctly you want to apply a grouping maybe this link can help you http://msdn.microsoft.com/en-us/library/ms742542.aspx

Silverlight DataPager - Split Into 3X3?

I have a ListBox bound to an observable collection.
I also have a data pager bound to the itemsource of the list box.
I currently have the data pager set to only show up to 3 rows.
How would I go about changing the style ListBox style (or something else) such that I could have a 3X3 display? For example, the first three items in my observable collection would be displayed on the first row of the list box, horizontally next to each other, then the next row would contain the next three items in the observable collection?
Any info would be greatly appreciated.
Thanks.
Chris
It sounds like you want to use an ItemsControl with a WrapPanel (from the Silverlight Toolkit) in the ItemsPanelTemplate.
<ItemsControl xmlns:controls="clr-namespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<controls:WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Here's a short tutorial about the WrapPanel: http://blogs.silverlight.net/blogs/justinangel/archive/2008/11/05/silverlight-toolkit-wrappanel.aspx

WPF binding to individual 'rows' (not columns) of a datagrid possible?

I have a datagrid. A column of the datagrid is a simple <DataGridTemplateColumn> with its CellTemplate containing a <DataTemplate> which contains a <ComboBox> such as
<my:DataGrid Name="dataGridMain" AutoGenerateColumns="False">
<my:DataGrid.Columns>
<my:DataGridTemplateColumn Header="Food" >
<my:DataGridTemplateColumn.CellTemplate >
<DataTemplate>
<ComboBox Name="comboDataTemplate"
Text="{Binding Path=Food,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding Source={StaticResource resFoodLookups}}"
DisplayMemberPath="FoodName"
SelectedValuePath="FoodID" IsEditable="True" />
</DataTemplate>
</my:DataGridTemplateColumn.CellTemplate>
</my:DataGridTemplateColumn>
</my:DataGrid.Columns>
</my:DataGrid>
All is working fine. Each combobox is bound to a static list due to the ItemsSource="{Binding Source={StaticResource resFoodLookups}}" statement.
But my requirement is that this list will change from row-to-row.
That is: each time a user types a new entry in the combobox list on one row, I want to have it available in the selection on the next row.
Basically, I want to create a new list for the user each time the user inserts a new word in the combobox on any of the rows. (The combobox is editable).
Now, I can wire up the "ItemsSource=..." at run-time, but I'm only able to do this once thus the <DataTemplate> propagates the 'same' list to 'all' the comboboxes on 'all' the rows.
My thoughts are that I need to change the ItemsSource=... property on an object-by-object basis on each combobox that is created in memory after the DataTemplate has created them - but I have no idea how to do this.
What you need to do is perform 2 way data binding to your the ItemsSource, this way when the ItemSource is updated in one of the combo boxes it will auto update your original collection and therefore your other combo boxes as well.
What I normally do is use the MVVM pattern. It is worth some research if you are not already using a particular pattern on your application.
Using it to solve your problem i would do the following:
Create a ViewModel (Lets call it MyViewModel) which has a collection of values called 'MyComboBoxItems' (It is important that you use ObservableCollection for the databinding to work)
When I create the Window/Control that contains your table, I also create an instance of MyViewModel and set its the Window.DataContext=myViewModelInstance
For your combobox binding use ItemsSource="{Binding Path=MyComboBoxItems, Mode=TwoWay}

Silverlight: Datagrid like grouping in ItemsControl

Is it possible to group items in a ItemsControl or Listbox in Silverlight? These controls are bound to a DomainDataSource.
Or are there any 3rd party controls that do this?
UPDATE:
This is the sort of UI I am trying to create.
You can do this by using nested ItemsControls bound to a PagedCollectionView.
Say I have a datasource - MyItems - with fields: Category, Section and Option. I can create a PagedCollectionView from an IEnumerable(of MyItems) and tell it which fields to group by.
Dim original As IEnumerable(Of MyItems) = GetMyItems()
Dim pcv = New PagedCollectionView(original)
pcv.GroupDescriptions.Add(New PropertyGroupDescription("Category"))
pcv.GroupDescriptions.Add(New PropertyGroupDescription("Section"))
Then I bind my first ItemsControl to the PagedCollectionView
hisMyItems.ItemsSource = pcv.Groups
The PCV creates a nested hierachy like:
-Name
-Items
where Name is the value in the grouped field and Items contains the rows/objects in that grouping. I guess you could also create the PCV in xaml if you prefer.
The xaml would look something like:
<controls:HeaderedItemsControl x:Name="hisMyItems" Header="{Binding Name}" ItemsSource="{Binding Items}" >
<controls:HeaderedItemsControl.ItemTemplate>
<DataTemplate>
<controls:HeaderedItemsControl Header="{Binding Name}" ItemsSource="{Binding Items}" ItemsPanel="{StaticResource ItemsPanelTemplate1}" >
<controls:HeaderedItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Option}" />
</DataTemplate>
</controls:HeaderedItemsControl.ItemTemplate>
</controls:HeaderedItemsControl>
</DataTemplate>
</controls:HeaderedItemsControl.ItemTemplate>
</controls:HeaderedItemsControl>
I hope that makes sense. I have tried to simplify things from my actual app but I could have made some mistakes in copying it over. Obviously you could use normal ItemsControls or other controls too and customize with templates etc.
The DataGrid control supports grouping.
Tim Heuer has a good blog on grouping with a datagrid.
link text
Perhaps the control you are really looking for is the Accordian Control from the Toolkit.
See sample of Accordian behaviour here.
Note that the actual appearance is as style-able as any other control. The basic function is to group categories of items that would otherwise be a straight-forward List.

Resources