WPF App with responsive design - c#

I want to make a WPF app which has a different position of its controls depending on the size of the window.
If MainWindow has Width above, let's say 500, then I want my Grid to be 2x2, and if it's below 500, then 4x1 (4 Rows, 1 Column).
First I made 2 Grids, one 2x2, the other 4x1. I have 4 different UserControls, which represent View part of the MVVM. I thought I'd use VisualStateManager with 1 group, which has 2 states, one for defaultGrid, the other for narrowGrid. First state sets Visibility of the first Grid to Visible, and the second to Collapsed, and the other state reversed (Do I even need them both to do that?). I put GoToElementState in the handler for SizeChanged event. I saw this in a book, but they didn't use UserControls, instead they just copied all the controls from the first Grid into the second one and changed the Row and Column properties for each control. I thought that it's possible for 2 different Grids to share 1 UserControl (that was actually the only reason why I put a dozen or so controls/elements in those 4 UserControls in the first place), but so far I've found that that's not possible (although I could be wrong here).
Now, for some controls I guess I don't mind that I technically have 2 instances of each UserControl, because the bindings make them synchronized, but if I type something in the TextBox and change the window size/visual state, then in "that same" TextBox I have different text.
I've come to the conclusion that I don't need VSM at all and that I don't need any other Grids besides the root Grid. In the handler for SizeChanged I've made rootGrid be either 2x2 or 4x1, depending on the window width. In MainWindow.xaml.cs I've also made those 4 UserControls private fields and instantiated them. They are changing their Row and Column properties according to window width. By doing that I now always have only those 4 UserControl instances, that just change their position in the app. (I don't need multiple instances of any of those UserControls).
What I want to know is: Is there any better/more elegant/possibly conventional way of doing this, that I haven't found?
I had the idea of making just 2 UserControls (2 Views) and using VSM to represent them. Both Views would bind to the same properties of the ViewModel. "Synchronization" of inserted text in the TextBox or selected item of a ComboBox would then be done, for TextBox for instance, by binding the Text property of a TextBox, of the first View, to the Text property of a TextBox of the second View. But this doesn't seem like a better alternative.
I also had the idea of making custom converters for Row and Column bindings of UserControls, but that seemed even worse.
Btw. I'm using C#, VS 2013 and Windows 7. I know UWP have interesting stuff with AdaptiveTriggers in VSM, but I haven't switched to UWP yet, I just started playing with WPF a month ago.
Also I can't use WrapPanel because I need these controls in exactly 2x2 or 4x1 grids. And I can't use UniformGrid because I need them in specific order.
Any input on this would be appreciated.

Related

Combobox for single data, but multiple representations

I am not sure combobox would be the best vehicle for tackling this problem, but visually it is appealing.
Consider such data as angle -- I could enter its value in radians (single editbox) or in form of degree, minute, second, millisecond (4 editboxes) -- there are other representations, but those two will suffice here. For now I have combobox with mode entries "radians", "DMS" changing mode shows/hides appropriate control.
This approach has two flaws -- it takes a bit more space (for extra combobox with modes), and since each control is different is size everything on right of it moves.
So I am thinking about more direct approach, instead selecting mode, which in turns switches visibility of given control, would it be possible to put each control inside combobox, and combobox would then select that control. The target data would be exactly the same for each row (angle), but each row would have different control, because each row would mean different representation.
Is doable with combobox or am I banging at the wrong door? If combobox is suitable for this task, how to do it?
I was so focused on data binding at the combobox level that I didn't notice that the solution uses the basics of combobox.
So first, for the moment forget about combobox binding to anything -- simply per each row define ComboBoxItem and put any control you like. In effect you will get multiple controls for the same data.
At this point the only missing part is selecting the mode. Since I no longer rely on manually switching visibility of the controls (combobox does it automatically) then I can bind to SelectedIndex and convert it only fly back and forth to mode.
Please note combobox is not bound per se to the actual data (angle in this case).

Extremely slow performance with multiple user controls

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.

Add label to textbox custom usercontrol in WinForm

I am writing a windows forms application that has a lot of textboxes. I want to add a label or a caption to the textbox, so that I don’t have to drag a lot labels onto the form and deal with positioning etc. So far I have found 2 possible ways to do this.
Create a user control with the label and textbox. How do I get the
control, label and textbox to size appropriately depending on the
text entered since the control will be reusable and different text sizes will be entered. How to get all the
properties and events of the textbox to remain the same.
Extend a normal textbox and add a string property called label or
caption, and show this property at the left of the textbox. I know
this can be done in Web.UI with CSS but is it possible in a winform
and how?
Any suggestions on how to do either of these?
Thanks.
You can create a UserControl that contains a label and a textbox. When you add the user control to your form, both the label and the textbox within will be added simultaneously. You can expose properties of the label and textbox to assign values at design or run time.
Using this method, you can add multiples of the user control to standardize the layout. As far as resizing the controls based on the text, you'll have to subscribe to events and change the sizing manually.
For example, you can subscribe to the TextChanged event of the label and the textbox. When the event fires, you calculate the size of the string and then adjust the width and position of the controls accordingly.
If you get to the point where you have too many textboxes, I would suggest switching to a DataGridView. The GridView component is very well suited for what you're describing, but of course it requires you to accept a grid layout.
One of the bonuses involved in using a GridView is hard to appreciate until you see it in action: it creates only one HWINDOW at a time (two if you're in editing mode). If you create Labels and TextBoxes all over your form, each one is registered with the operating system as an HWINDOW object. All those HWINDOW objects take time to display! In .NET 1.0, WinForms was so slow that dialogs with more than about two dozen controls were unusable. Even though .NET 2.0 is much better in this regard, but you'll still get significantly better performance by using a single control that manages lots of data, as opposed to lots of controls that each manage one piece of data.
Oh, and another option, if you like: you can also try a PropertyGrid. It has the advantage that it will also show help and allow you to create complex editing controls for each element.

Auto Layout Increasing Number of Controls

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.

What is the best way to embed controls in a list/grid

I have a table of about 450 rows that I would like to display in a graphical list for users to view or modify the line items. The users would be selection options from comboboxes and selecting check boxes etc.
I have found a listview class that extends the basic listview to allow for embeding objects but it seems kind of slugish when I load all the rows into it.
I have used a datagridview in the past for comboboxes and checkboxes, but there was a lot of time invested in getting that up and running...not a big fav of mine.
I am looking for sugestions how I can do this with minimal overhead.
thanks
c#, vs2008, .net 2.0, system.windows.forms
If you have a complicated set of controls for each row, this is the simplest way to do it. However, it won't act like a listbox; you won't be able to highlight your rows or navigate with the keyboard.
Create a usercontrol with public property to point to your row
Draw a panel on your form - you will add instances of your 'row' usercontrol at runtime to this panel.
Set the panel to autoscroll (also set property to make the active control scroll into view)
Set the panel's Anchor property so it sizes w/ the window
You can set the form's max/min size properties so the full usercontrol row always shows (have to do to prevent horiz. scroll bar in panel)
Have a routine to add the rows
In a loop, create new usercontrols, set their properties, including the row in the datatable
Also, set the .Top property to the panel's .controls(pnl.controls.count-1) for all but the first one you add
Very simple, allows complicated 'rows', gets the job done. There are better ways to do this if you want listbox-like functionality without coding it yourself, but you may not need that.

Categories