With a DataGrid object in WPF, we can bind its rows to an observable collection such that as rows are added or removed to/from the collection, the UI updates to display the changes. I am looking to do something similar with a Grid control as part of a User Control I am trying to create. Is this possible?
If you want to bind a collection to some sort of self updating UI in my experience an ItemsControl with custom ItemPanel and a ItemContainerStyle with a Template set as well as ItemTemplates for different kinds of objects in the collection is quite powerfulI.
It all depends on your exect scenario though. If you can elaborate i could whip up some XAML.
Related
I currently have a class object that is bound to a listboxitem. Before I used to get the other objects inside the ListBoxItem by clicking a button and accessing its parent, but now I need to gather the objects without clicking the buttons or labels, just by its class.
I've tried to gather the ListBoxItem with its index and its class binding, but both of them is giving me a null value:
ObservableCollection<ClassBinding> classList = new ObservableCollection<ClassBinding>();
... adding items here to the collection;
listBox.ItemsSource = classList;
ListBoxItem lbi = (ListBoxItem)listBox.ItemContainerGenerator.ContainerFromIndex(index);
Is there another way to access the listboxitem to later gather the other objects by using the function FindName(...)?
Debug:
TextBlock delay = lbi.FindName("lblDelay") as TextBlock;
Error:
Output: Exception thrown: 'System.InvalidOperationException' in WindowsBase.dll
A ListBox is virtualized by default, see Displaying large data sets.
Typically, you do not have to display all the items at the same time; instead you display a subset, and the user scrolls through the list. In this case, it makes sense to use UI virtualization, which means the item container generation and associated layout computation for an item is deferred until the item is visible.
In other words, you get null, because the ListBoxItem in question is not yet visible and realized. The only reliable way to get around this is to disable virtualization to force instantiation of all items. Although you can then access each item, this can result in bad performance for large collections, since all items are loaded when the ListBox is loaded and all items are held in memory which increases the memory footprint.
<ListBox x:Name="listBox" VirtualizingStackPanel.IsVirtualizing="False">
Accessing child controls, e.g. in data templates by name with FindName(...) does not work in ItemsControls like ListBox. You will have to walk the visual tree to get the controls, see:
How can I find WPF controls by name or type?.
In general, it is not a good idea to deal with controls in an items control directly. It is much easier to use data-binding, where you will not have any issues with containers and virtualization as you do not access them directly. Furthermore, your code will be simplified and you do not need to assume a visual structure.
For more information and examples on this topic, you can refer to:
How to: Bind to a Collection and Display Information Based on Selection
Data binding overview (WPF .NET)
Data Templating Overview
WPF Databinding With A Collection Object
In order to find another solution/idea for this I came up with the INotifyPropertyChanged that can be added inside the classes, so there's no need to remove the ItemsSource from the list box, just hook the items source at the load of the program and then you can change the data inside the collection.
I used the code from here: INotifyPropertyChanged and ObservableCollection WPF
I didn't need to access the text blocks, just hooked some bindings to the objects and was able to do UI changes from just changing the values of the classes.
I'm creating a WPF program that consumes rest api data. I want to implement lazyloading and infinite scroll on the data and programmatically create and add either custom data templates or listitems very similar to this design
I'm just confused as to which approach to take and what benefits/costs each provides
Easy choices:
Everyone uses MVVM so use MVVM.
Data Templating is a fundamental of wpf and building UI in code is not recommended - so use data templating.
You can dynamically add templates to resources by building xaml as strings. This is the MS recommended way to build any dynamic UI. Those strings can come from flat files, a database directly or a web service and you can build them by manipulating txt files or serialising controls.
A huge plus of this is you have the markup "right there". So when things go pear shaped you can paste into an experimental solution and see the errors light up in the xaml or see what the user is seeing.
If datatype associated templating doesn't suit for some reason then you could write a datatemplateselector and put your logic in there.
I'm not sure how you expect that to scroll exactly but I'd go with a listbox, some datatemplates associated with a type per view. Assuming the items can have different views - you just seem to have that "gilded" button or tag as an option.
Load your data into viewmodels with one per row.
.Add to an Observablecollection which is a public property in a viewmodel.
Bind that to the itemssource of a listbox.
They are then templated into UI.
A listbox has a scroller built in but you could re-template if you wanted to scroll using some other approach.
A StackPanel is a Panel that arranges child elements into a single line that can be oriented either horizontally or vertically.
A ListView is an ItemsControl that you can bind to an IEnumerable of objects and is used to present a collection of items.
What you should do is to create an ItemsControl with an ItemTemplate that corresponds to a scrollable item in the list. There is a basic example available here and you will find a lot more examples online.
I have a ListView with a GridView in my C# WPF application. The ItemsSource is bound to a ListCollectionView created on the ViewModel from an ObservableCollection<MyClass>. I use the ListCollectionView for dynamic sorting, filtering and grouping, all of which can be adjusted or turned on/off from the View.
When I alter the filter or turn the grouping on/off, all of the visual list view items are recreated, which causes the UI to freeze for about a second. Since I have about 250 items displayed and there are about 10 columns (some of which have cell templates with a progressbar), this comes as no surprise.
Now, I know that the obvious answer is to enable virtualization. This however, brings some undesirable effects, such as scrolling becoming jerky or the scroll-bar changing its size as you scroll (this happens with grouping on, since the groups vary in height and so the virtualizing stack panel can not calculate the total height properly at first).
What I would like to do is to have the ListView keep a visual element for every item in the raw list (un-filtered and un-sorted, i.e. the ObservableCollection<MyClass>) and then only add to or remove from the visual tree depending on the changes in the ListCollectionView.
I hope this solution should boost my app's performance, since I rarely change the raw list, but I often alter filtering, sorting and grouping.
Do I need to create a custom control inheriting from ListView (or GridView) to do this, or is there another way?
Try to use DeferRefresh, this delay automatic refresh until the defer cycle is existed. See if that helps.
CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(SomeListView.ItemsSource);
using (view.DeferRefresh())
{
view.GroupDescriptions.Clear();
view.GroupDescriptions.Add(new PropertyGroupDescription("Country"));
view.GroupDescriptions.Add(new PropertyGroupDescription("Active"));
}
http://blogs.msdn.com/b/matt/archive/2008/08/28/collectionview-deferrefresh-my-new-best-friend.aspx
I am quite new to WPF and XAML but my background is of ASP.NET and C# so I have a vague idea of how it works.
In .net, I can use the repeater, datalist, gridview, bind to them a DataTable and output from that DataTable. I am now wanting to do the same with WPF.
Basically, I want to display simple records from a database (preferably using a DataTable as I usually work with those). The list might be something like this with two columns
1) Grey TV
2) Red car
3) Blue motorbike
I have looked around but I can't get a definitive answer on what control to use. Some people say ItemsControl and some people say DataGrid. Can anyone help me here?
Thanks in advance.
A DataGrid is used for displaying Table-like data (Per record multiple columns). An ItemsControl is used to display data using your own ItemTemplate, in which you are unlimited in how to represent the items and in what directions or alignments.
Another good useable control for you might be a ListView, which works just as a ListBox except it doesn't have any selection logic. And you can choose between four different ways of displaying your items using the View property (http://msdn.microsoft.com/en-us/library/system.windows.forms.view.aspx).
In your case I would suggest using a ListView.
To bind any items to the control, you have to set the DataContext on the UserControl or the Control itself. And then bind the ItemsSource property to a local List or Collection using the Binding markup extension (http://msdn.microsoft.com/en-us/library/ms750413.aspx). To learn more about data-binding go here:
http://msdn.microsoft.com/en-us/library/ms752347.aspx
I'm very new to WPF, and am trying to set the datasource (which the WPF Grid doesn't have as a property) of my grid to take a List. Does anyone have any code examples of how to do this. I have googled it, but can't find any really good examples.
(Oh, and can anyone suggest a good site for all round WPF Code examples?)
Thanks
If you're referring to a WPF Grid, you can't bind it to data; it's meant for layout purposes only; you might want to look into one of the controls that inherit from ItemsControl, such as ListView.
The property you'd bind your list to, is called ItemsSource.
The other control you might be thinking of is the GridView
There's also the DataGrid (Note old link) in the WPF Toolkit which implements a lot of the same functionality as the WinForms DataGridView