How can I add column headers to a Silerlight ItemsControl? I need a fast way to display a List of items that contains also some header info.
This may seem like a simplistic question but why not use the DataGrid in readonly mode?
The downside with data grid is it doesn't use a virtualised ItemsControl so performance may suffer if you are trying to list hundreds of items with many columns.
There's nothing built into the ItemsControl itself, but there's nothing to stop you from making a custom control that has that kind of functionality. It's a little work up front for the ability to reuse it later if it's a piece of UI you need frequently.
Adding too much functionality to it might be overkill though; if you need column sorting or automatic column/header generation, you may find that a DataGrid (as Anthony pointed out already) would be a faster way of getting a lot of functionality for free.
Related
I've got a massive UI that I'm designing. The way that my employer wants it, there are at least 100 labels. Now, I've always thought that in cases like this, breaking up the UI into smaller custom controls was the ideal way to go. However, someone recently told me that custom controls are really only for code re-use. What is the actual suggested practice for this?
EDIT
The finished form will look like this:
Now, I'm using WPF for the UI, and I'm thinking of breaking this down into smaller bits.
Based on your image i see some repetitions, each of this repetitions could be a custom UserControl
But it depends on the usability is it easier to write a custom UserControl so do it but if it would reduce the readability of your code and it also adds additional complexity don't do it
here are an example of what could be separate UserControl's
the green ones are possible useful encapsulations of logic
the orange ones maybe need some not market stuff (don't know enough about your software)
the red ones are the maybe's based on the intern use (from the visual part they are repetitions so the should custom UserControl)
Since your UI is read-only, I'd suggest using a grid.
Are you new to WPF? To break the View into bits WPF offers you CustomControls and UserControls. They are two very similar things yet completely different from each other. CustomControls are Buttons, Labels, TextBoxes, DataGrids...etc. They are basically simple stand-alone controls. UserControls are groups of stand-alone controls serving a purpose such as example a Button and a ComboBox next to each other so user can select something in ComboBox and confirm that by clicking the Button.
If you wish to display data from database I suggest you DataGrid which will give you a table-alike look with rows and columns and all that. If you wish to place few buttons next to DataGrid on which the user may click to insert a new row or to edit a certain cell then I suggest you to wrap all that with a UserControl which you can reuse in other places where you have to display and change data from database too.
You should be using a datagrid and can customize its template to render individual cells as Textblock (lighter version of Label) from a rendering perspective. The main difference between Textblock and Label is very minor things such as access keys and disabled state behavior. But from a WPF object hierarchy - Textblocks are much lighter. But besides that point - from your employer perspective - once you have customized the grid template and render them (so as they look as textblocks/labels) - your employer should have no problems.
Also as somebody suggested above - if you want to logically break sections of the UI since they maybe coming from a different table in db - then User controls is the way to go (for maintainability of code)
Let me know if you are looking for more technical details or need help further technically.
There is nothing wrong in making and using custom controls or user controls or defining some data templates which will be reused depending on how your data is organized.
For sure the UI looks pretty messy and some sort of grid should be used with templates for example where there is similar data. I also have the suggestion and first think about the data and the functionality before starting and let the UI be driven by that. For sure you will the reuse controls/templates. If you think in front on the model and behavior the UI can afterwards more easily changed.
Create your viewmodel correctly, implement the functionality in commands, use bindings, after that the UI will come naturally, reuse controls, use several grids, make the UI more user friendly using several regions, tabs, windows or anything that makes the user more comfortable.
We're rolling our own special Items-based control/panel combo that isn't based on a subclass of ItemsControl (there are multiple reasons why we can't do this which I won't get into here) but our control does handle thousands and thousands of data items, so we'd like to implement Visual virtualization.
What we're wondering is if it makes more sense to try and bang the existing ItemContainerGenerator class into our design or roll our own virtualization method.
On the one hand, ItemContainerGenerator already handles virtualization and is very efficient, and tried-and-true code is almost always preferable to starting from scratch, but on the other, the ICG was designed specificially for use with, and relies on features of the ItemsControl, which again, this control is not. Plus, that is a container generator but in our case, we just need to generate and lay out a specific, known visual that represents the data item.
Now, perhaps I'm over-simplifying things, but all I see is a need to determine which items would be visible in the ViewPort, ensure visual representations of those items are created, measured and arranged, then discard any left-over already-created visuals. To keep track of it all, it seems a simple item-to-visual mapping scheme is all that is needed, perhaps with a ItemVisual attached property on the DataItem's ViewModel object. That way when an item is removed/destroyed, we just check if there's an existing visual, and if so, nuke it.
That said, can anyone think of a reason we shouldn't simply roll our own visual virtualization? Again, the ICG does this, but I'm wondering if that's taking a Semi to the store to get eggs.
I have always been using a Syncfusion virtual grid which works on the basis of an override on that grid that is fired for each cell that is visible! It provides me with information on the row and column and some cell object that lets me set the value of that cell, its formatting, colours etc.
This allowed for very fast scrolling on very large datasets, since I simply have to 'read out' the value like dataSet.Tables[0].Rows[1000000]["LastName"].ToString()
Is there anything similar exposed by the WPF DataGrid?
EDIT
I need to make myself clearer - I know about virtualization and that it switches itself off when you do grouping etc. Having run a test with grouping enabled over a dataset of 20,000
rows made my grid choke on itself.
Therefore my previous question stands on its own!
Is there any way the grid allows me to fill in the text and do some formatting through some override or callback?
Thanks
The DataGrid uses virtualization by default. This works by either creating and deleting cells on the fly or by recycling the visible cells and repopulating them with the current row's data. This can be turned off as well as tweaked by playing with the 'VirtualizingStackPanel.VirtualizationMode' property and is forced off in many situations (grouping is a good example). This virtualization can be a godsend and a curse. If you have a simple set of requirements, then it makes it dead easy to get good performance. If on the other hand you are doing complex runtime binding, including triggers and custom columns, then it becomes a bit of a nightmare.
a couple of important reads:
http://msdn.microsoft.com/en-us/library/cc716879.aspx
http://msdn.microsoft.com/en-us/library/system.windows.controls.virtualizingstackpanel.aspx
I am new to WPF environment and I am experiencing some problems like if there are alots of things how do we manage them.for example I have three borders each of same size same location and they contains controls like textboxes etc etc we construct them sequentially but when it comes to edit we get in trouble modifying the border that is at bottom.
So in short how do we manage many controls on single page so that it remains easy to edit
Not sure I completely understand your concerns, but here are several point that make editing WPF UI pretty easy:
Correct usage of layout panels. If you will use approach with absolute positions for each control then it might become a nightmare to move or resize some of your controls. Correct layout (and panels such as DockPanel/StackPanel/etc) might help you a lot.
Incapsulating repeatable parts. WPF has a lot of feature to avoid repeating UI code. I'm talking mostly about Styles and Control templates at the moment. If you have your borders repeating through the entire window, maybe you should think on extracting this border as a ControlTemplate for ContentControl for example?
but I've found that encapsulating controls such as borders, textboxes etc in User Controls helps to keep things well managed (not to mention helps reduce code), similarly using a Resource Dictionary to store styles/animations is useful for very big projects (remember though that the local resources will take precedence when applied so remove them if they not in use)
furthermore, using Layout Panels such as Stacks,Grids and Dockpanels allows you to collapse User Controls when not needed or otherwise (also I've found that for some reason, Grids allow controls to overlap (when items are not correctly ordered in Grid Rows and Columns) which can lead to some elements not being seen in design.
Plan your layout properly and think through which Panels would be best for them, having to go back much later and change can be annoying (though admittedly it happens).
Also remember to use partial classes to properly structure your stuff, having to read through 1000+ lines of code to find something can be a nightmare.
I'm looking for way to present equally sized elements in a fixed number of rows and any number of columns. (Think of iTunes' or Picasa's album view. I believe some platforms refer to this as a 'gridview')
A WrapPanel would do the job, but I'm binding against a very large collection of objects, so I need virtualization.
I've been looking around the web, and found both commercially available VirtualizationWrapPanels and blog posts on how to implement your own VirtualizationPanel, but I can't seem to find any simpler solutions.
Is it possible to arrange virtualized databound items in a grid-style view (fixed number of rows) with standard WPF components?
I've recently had to have a hunt round for similar functionality and struggled to find anything that was production ready.
I found a series of articles and sample code that contain a Virtualizing Tile Panel.
I've been using it and it has been fairly stable. There were some changes that needed to be made though. We had to add some of the keyboard control into the panel as it wasn't implemented, tabbing needed to be changed as well as adjusting tile sizes, etc. It's a good starting point if you decide to roll your own.
One major caveat though was that it also MUST have a parent that is constrained to a limited size else it errors out. This is not normally an issue as you will want it to be limited in size so you can enable scrolling. There may be a solution to this particular problem but we didn't have time to investigate.
A quick-and-dirty solution is to use a list (in your case a horizontal one) of "grouping items" (in your case vertical ones) which will determine desired number of rows. Virtualization will occur on the "groupers".
It is the responsibility of the Panel to provide Virtualization. Unfortunately the framework only provides a virtualizing StackPanel:
http://msdn.microsoft.com/en-us/library/system.windows.controls.virtualizingpanel.aspx
There is a very good blog post that provides a virtualizing WrapPanel here:
https://blogs.claritycon.com/custom-panels-in-silverlight-wpf-part-4-virtualization-7f3bded02587
Another alternative is to use a DataGrid, this will virtualize for you.