I've put together a scheduling application similar in style to that found in outlook, however it can show the schedules of multiple people. I have written a user control, basically a Border with gradient filled background & TextBlock. One of these controls are added to a Canvas at a set location for every appointment. The trouble is, I will have multiple users, with multiple appointments and may need to display 1000 or so appointments at a time. Initially, it takes an absolute age to instantiate all of these objects, however, I can live with this.
Unfortunately, the big problem arises when I try to scroll through the appointments. I have a couple of buttons to scroll left and right and upon clicking these, the UserControls' Left position are moved left or right a certain number of pixels - it can take several seconds between clicking a button and repainting(I also tried with labels just to test, but it was the same).
I guess the real question here is how to implement an interface, showing hundreds of controls with adequate performance and if this isn't achievable, how would I approach such an UI.
One possible option is a TextBlock CustomControl. You can get the exact same style as you have in your usercontrol but with a somewhat faster loading time.
Without a good, minimal, complete code example that reliably reproduces the problem, it will be difficult if not impossible to completely understand the performance problem you are having, never mind provide a solution.
That said, from your description it sounds like you are really looking to present the user with some type of ItemsControl, such as ListBox or ListView (a specialization of ListBox). In an ItemsControl, you can specify an ItemTemplate that defines how each item in the list will appear; this is analogous to the UserControl you apparently are using now.
I believe it's likely it will work fine just with that change alone. I.e. define your per-item visual as a DataTemplate instead of a UserControl, and set the ItemTemplate property of e.g. your ListBox to that template, then just bind your collection of appointment objects to the ListBox.ItemsSource property.
Note that the ListBox class already defaults to using VirtualizingStackPanel in its ItemsPanel template. So you should have no performance problems at all with this approach if you use ListBox.
If you want to use a different ItemsControl or create a custom one, you may or may not find that you need to use a virtualizing panel object explicitly (such as the VirtualizingStackPanel that ListBox uses). With just 1000 items in the list, even a non-virtualized panel may be fine, but if not then even when not using ListBox, you can always specify it explicitly.
Related
I am currently on the topic of creating a Combobox that expands with a full treeview where one can select a topic
It is for category selection.
The current approach just displays all "expanded" upfront with different margin depending on which level they are (utilized using itemcontainerstyle margin and a converter)
However, that is not what I want it to be as it tends to grows extremely large with larger category trees
Thus I am searching for other solutions
I could write a custom control but I also face issues in understanding how the selector controls actually get build
Thus my questions are:
Is there a way to get a combobox having a treeview for selecting instead of an itemscontrol?
If no, how to implement the selector properly (could also just derive from control and build it myself, but that would require more work and casting the control to selector etc. would not be possible --> some attached properties are not working then)
I have integrated a feature in my tool that allows me to expand all recursively. I realise this would generally be a slow process anyway but currently. I have maybe 100 nested controls which are all expanded at once, so calling Expand All means that each control/datatemplate etc is processed at once.
This causes the tool to lock up for a good 10 seconds before responding. Of course, once the view hierarchy has been constructed, its then fast (I can collapse and expand instantly from then on). But it seems a little odd that there isn't a faster way to generate large forms, I wouldn't consider 100-500~ controls very many.
I have looked into virtualisation, but it doesn't appear to be useful to me in this case because all controls are expanded at once. Its fine if I expand them on a singular basis.
Edit:
Updates we're needed to the question to describe what the layout of my window is:
I have a number of TextBoxes, ComboBoxes, Sliders which are all nested inside of a number of Expanders. Each expander can contain N number of expanders, this is recursive to an extent. Depending on how the data is laid out. Some of these data types (which are represented by datatemplates) may contain StackPanels if needed and numerous grids for layouts.
To expand all it simply means to iterate each expander (which IsExpanded is bound to an IsExpanded property). I set this property on each data type (and its children) to true. And let the binding do the work of expanding everything. This causes every single control to be added at once.
Thanks
So after reading the edited question, I have a guess what's going on:
The UI is busy on rendering controls. And I assume there's not much data kept behind in viewmodels bound, so the data is not the point in your issue.
When the Expander control gets IsExpanded = true the first time, Xaml is parsed (object / resource parsing, not compiling) and visual tree children are created.
100-500 visual tree elements is a high number for rendering, because each of them (if it's belonging to the System.Windows.Controls namespace) consists of many sub-controls (Border, Grids, TextBox,..).
What you can achieve is NOT shortening the expanding time, but to unblock the UI:
advise the dispatcher to handle IsExpanded asynchronously and see how it behaves. This requires that you don't use the expanders default action:
In the arrow button click handler, skip default handling and insert this (IsExpanded is your bound viewmodel property here):
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(
() => { this.IsExpanded = true; } ));
I am somewhat new to WPF and hopefully I'm not asking for the world here but I'm looking for advice/direction on how to go about implementing something like the following.
I'd like to have my MainWindow contain N buttons. Each Button performs the same action on a different set of data (i.e. print picture 1, print picture 2, ... , print picture N). I'd like my window to automatically layout the buttons as described below:
Note how the number of buttons increases, the layout automatically adjusts in a pleasing manner. Up to 6, and then the it provides a horizontal scroll to shuffle through the buttons.
I feel like the <Grid> control might be the way to provide this but I'm lost in how to get the automatic layout tweaks short of a lot of brute fore.
Tangentially, I see the power in Data Binding in WPF and ideally the button's info (it's display text, graphic, etc.) would be automatically binded to an observable collection so that as I insert buttons into the collection, the UI automatically updates. Conversely when each button is clicked, I'd like to have a generic handler know button 5 maps to the 5th element in my collection which has all this additional info (i.e. the file name of the picture to print).
That all sounds well and good but again I'm lost a bit in the implementation.
As Allonym said, the most customizable way would be to create a new custom Panel for this.
IMHO, it may also be possible to achieve this using a UniformGrid, and tweaking it a bit with bindings and converters. That is for the layouting.
About your second question, I think using an ItemsControl is the best way. You could pass it your new Panel (or UniformGrid) as its ItemsPanel. Also, you could then create a DataTemplate with a button inside, bind its Command property to a single command (= generic Handler), with as parameter the DataContext of the DataTemplate (= the current item of the list). This part is easier than the layouting.
Does is help?
Antoine
I think you'd have to create a custom Panel class, overriding MeasureOverride and ArrangeOverride to achieve your desired layout. Check out this (very brief) tutorial.
This is a getting started question about how to create a reusable wpf slideshow control:
that displays a sequence of any visualizable elements e.g. a series of Image controls or a series of UserControls (should I target ContentControl, or is there a broader type that encompasses more visualizables/controls?)
the control should be able to accept an IList of some kind, which would be the elements/slides to present
the control should expose an Interval property that determines the duration of each slide, but i dont even know the basics of how to get started with that in terms of offering that property to be configured in xaml?
and what should the container be, if any, for the individual slides/controls that are passed in?
To start with, you should probably create a UserControl which contains an Image control, and perhaps Next/Previous Buttons, and anything else you may need. These would all be laid out as normal using a variety of panels, you could probably style most of it with just a Grid.
After that, your UserControl will implement the ImageSource (your IList, or IEnumerable of images), and your interval as dependency properties. These are then settable in XAML.
You would then write the logic which loads the next image and sets it as the Image's Source property, this could happen in the change event for the ImageSource property. You can then get as advanced as you wish with Image preloading/caching etc.
I've just delved into WPF myself for a "Slideshow" like project where I'm showing customer order numbers on screen for a period of time before showing the next, and using Effect/Transitions/Storyboards to move to the next frame. I found a good article on CodeProject
I used a Grid with 2 rows:
Contains my "Changing area".
Contains static information (logo, controls etc).
Rememeber to set "cliptobounds = true" on your changing area if you use any sort of transforms on it. (I know you said you aren't using transitions initially, but once people see it, they'll be asking).
Dependency properties are also easily built in C# if you just type propdp and hit tab.
I would like to store and display a list of complex items. Each (graphic) item has to display an image, a list of color chips, a label and an index (a letter). User would also be able to zoom within each item, to show details of the image (on mousewheel),
Items would be presented in a vertical list, scrollable and resizable.
Language is C#, .net2.0, or 3.5 only if necessary.
I'm think about using custom UserControls for items (each one composed of a PictureBox, 2 Labels and a custom UserControl to display color chips).
For the list, I really don't know what to choose between a ListBox, a ListView, or a DataGridView, or another one I don't know yet.
I basically would go for a ListBox for its simplicity. Could you help me clarifying the advantages of using other lists?
If you expect to have a large number of these items, I strongly recommend that you do NOT make each one a UserControl. This is doubly important if you intend to localize and globalize the application at some point. The creation of these items will hinder performance.
Instead, take a lighter weight approach so that the items don't have the overhead of a full-blown control. Assuming that each item will be rectangular, you could easily create a UserControl for painting them, including a scrollbar to scroll.
in your case a custom (third party) list control seems to be the way to go. ListBox, a ListView or DataGridView are rather too limited given your requirements.
Regards,
tamberg
Thanks for your answers. It's very helpful to me.
I'm sorry I didn't mention that the list and its items have to manage drag-dropping with other controls. Then, I suppose that items have to be separate controls. Also, list would be dynamic and would not contain more than 30 items.
So, if I understand your advices, I should create a custom UserControl for the list and one for the item.