I've thoroughly checked the custom controls topic, spent several hours looking into custom controls written by other people. I've written my own custom button, to feel it better. I've read all the google answers around the "why custom controls", "advanced custom controls examples" and such.
My question is, WHY?
Why would I (or anybody) go through 9 circles of hell to create his own custom control, when one can just adjust an existing control to his needs (using styles and templates). I actually didn't find any explanation on google, just tons of examples, mostly from people who sound even less educated than me.
I imagine there IS such need, when talking about some complicated DataGrid with, I don't know, every cell being a button or something (and still I believe I could do it with a regular DataGrid)... But I've not found anything more complex than a beautiful button. Is there nobody sharing a complicated code on the topic?
There are different levels of element customization in WPF, depending what class you extend from. Each has its own uses and is implemented differently. It is not clear from your question if you are asking about a specific type of control or about all of them in general. So, I will tell you what I think about different ones.
UIElement or FrameworkElement
Extending UIElement gives you the lowest level custom control where you have complete control over the layout and rendering. FrameworkElement is slightly higher level as it does most of the common layout stuff for you while also allowing you to override key parts of it. The main idea with these is that they do their own rendering rather than composing other elements together.
I have made a number of custom FrameworkElements over the years. One example is a ruler similar to one you might find in a program like Photoshop. It has a bunch of properties providing customization for how it is displayed as well as showing markers indicating mouse position relative to the ruler (and a number of other little optional features). I have used it in two different professional projects. I think the main benefit is that it is extremely easy to drop in and set properties/bindings on wherever desired. Build it once, use it over and over.
Control
Extending Control introduces the concept of compositing multiple elements/controls into one reusable component via control templates.
I have used this one less often, but still find it very valuable in the right circumstances. Again, the main benefit here is reusability. You create a control with properties that make sense for what you want to do, then hook up those properties to the properties of the controls in it's control template. Really, this is the same as applying a new template to an existing control, with the added feature of being able to define your own dependency properties. You also have the ability to perform custom logic in the control's code if you need to.
I may be misreading some of your text, but you seem to imply that making a custom control is considerably more difficult than making a control template for an existing control. I have found that the two are nearly identical in most cases using this approach, the only difference being whether you have a code behind you can use.
User Control
A user control is really only slightly different from a custom control practically speaking. Only, instead of defining a control template, you define the visual content directly.
This is probably the most common type of custom control. It is basically the standard method for making XAML based content in a WPF application. These can be reused like other controls, but are more suited for single use such as the content of a dialog or window or something else that is specific to a single application.
Some Other Control
You can also extend an existing control to add additional functionality to it. This way, you still get all the features the control offers and only have to implement the additional bit.
For example, I have a custom control called an AutoScrollRichTextBox that extends RichTextBox. So, it does everything a RichTextBox can do. It also has the ability to automatically scroll to the bottom when content is added to the text box (which it only does if the text box was already scrolled to the bottom before the addition content was added).
I could have implemented that feature as an attached property instead of an extension of the control (and maybe I should have), but it works, and I have used it in three different applications (as an output window and as a chat log). So, I am happy with it.
In the end, it really is just a matter of how self-contained, reusable, and easy to drop in you want a control to be. If there is already a control that does what you want, and you just want it to look different, then you should definitely use styles and templates to achieve that. However, if you want to make something that doesn't already exist, limiting yourself to using only styles and templates will make the implementation work harder and make the end result less reusable and more difficult to set up additional instances (unless all instances are identical).
The examples of making things like buttons that look different are not examples of what you should use a custom control for. They are just examples of how someone would go about making a custom control for the purpose of teaching the details of the process. If you actually want a customized button, just customize a button.
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.
I have inherited a large MFC application which contains a CComboBox subclass that overrides OnPaint. Currently it does all its drawing by hand (with lines and rectangles), and renders a combo box that looks decidedly Windows 98-style. However, it otherwise works great and provides a lot of useful custom functionality that we rely on, and rewriting the entire control is probably not an option.
I would like to modernize it so that the OnPaint draws in Aero style where available (falling back to the old code when modern theming is unavailable). I've done this with some other custom controls we have, like buttons, and it works great for our purposes. I know there are some tiny behaviors that it won't get right, like gentle highlights on mouse-hover, but that's not a big deal for this app.
I have access to the CVisualStylesXP ckass, so I've already got the infrastructure to make calls like OpenThemeData, GetThemeColor or DrawThemeBackground pretty easily (via LoadLibrary so we don't force Vista as a min-system). Unfortunately, I don't know the proper sequence of calls to get a nice looking combo box with the theme-appropriate border and drop-down button.
Anyone know what to do here?
Honestly, I don't know why they originally tried to override OnPaint. Is there a good reason? I'm thinking that at least 99% of the time you are just going to want to override the drawing of the items in the ComboBox. For that, you can override DrawItem, MeasureItem, and CompareItem in a derived combo box to get the functionality you want. In that case, the OS will draw the non-user content specific to each OS correctly.
I think you best shot without diving in the depth of xp theming and various system metrics is take a look at this project: http://www.codeproject.com/Articles/2584/AdvComboBox-Version-2-1
Check the OnPaint of the CAdvComboBox class - there is a full implementation of the control repainting including xp theme related issues.
Not sure if it's the same situation - but when I faced this problem (in my case with subclassed CButtons), solving it only required changing the control declaration to a pointer and creating the control dynamically.
Let's assume that your subclassed control is called CComboBoxExt.
Where you had
CComboBoxExt m_cComboBoxExt;
You'll now have
CComboBoxExt* m_pcComboBoxExt;
And on the OnInitDialog of the window where the control is placed, you create it using
m_pcComboBoxExt = new CComboBoxExt();
m_pcComboBoxExt->Create(...)
Since this is now a pointer, don't forget to call DestroyWindow() and delete the pointer on termination.
This solved my particular problem - if your control is declared in the same way, consider giving it a try.
I need to show a similar-looking dialog in two different places in my application, one place as a modal dialog box and one place embedded into another menu.
From my limited understanding of WPF, it looks like Styles would allow me to write a single UserControl and customize its colors and fonts for both scenarios. However the changes are a bit more extensive, some of the element positions (for example, TextBox) are in different relative positions.
I am not sure if this can be done with Styles, or if there is a more appropriate way to do this in WPF. Worst case, I can write two completely different UserControls, but that is very bad in terms of maintainability so I'd like to avoid it.
Sure you can do it with styles/templates. Just give each of the styles a key and use the key to access the right style at the right place:
<YourUserControl Style="{StaticResource firstStyle}"/>
If you use a pattern like MVVM (I prefer MVVM Light) this is quite simple to do. You would write one ViewModel that captured all the data and behavior you wanted to expose and then create two views the way you want them, both using the same view model.
This scenario is one of the core intents behind the MVVM pattern. You're right that it is "bad" to write the behavior/plumbing twice, but the views are different, so you're not violating any re-use there.
I wanted to know which one amongst Style and UserControl would be better to use in WPF?
For example:
I have created an image button in two different ways.
One uses Style and ContentTemplate property is set.
It uses one other class with dependency properties.
The other way is I have created a UserControl which has a button and its content property is set.
The file UserControl.xaml.cs also contains the dependency properties.
For Code details see the answers of this question:
Custom button template in WPF
Which one would be better to use? In which scenario should one go for Style or UserControl or any CustomControl?
Styles are limited to setting default properties on XAML elements. For example, when I set the BorderBrush , I can specify the brush but not the width of the border. For complete freedom of a control’s appearance, use templates. To do this, create a style and specify the Template property.
Styles and templates still only allow you to change the appearance of a control. To add behavior and other features, you’ll need to create a custom control.
For example,
To create a button like a play button use styles and templates, but to create a a play button which will change its appearance after pausing it use UserControl.
For this type of thing I would go with Style, even though I'm not really adept with graphical tools. I tend to produce a basic, boring style that I can get started with and then prettify it once the application functionality has been verified.
The nicest thing about WPF is being able to distance much of the graphical look, feel and behaviour away from the code.
This allows you to change the style of your application without revisiting the code and indeed means that you can change styles on the fly at runtime.
There is an awkward line to tread with regards to how much behaviour is placed within the XAML and how much is placed within the code. A rough guide would be to decide on what behaviour must always be present within the UI and place that in the code, everything else place within the XAML.
Think of the code as being an abstract class with defined interfaces and the XAML Styles as being classes based on that class and you'll get an idea of what I mean.
Conversely, I know that people who are far more adept at the GUI work prefer to put more functionality in the XAML and others who prefer the code side, because they find the GUI work slow or difficult.
When thought of that way you'll see that there's never really a right or wrong answer, just better solutions that suit your skills.
In order to make a convenient UI for an .Net 2.0 Winforms application I am working on, I have need for a control that I'm pretty sure goes beyond the "out of the box" behavior of any standard control. A mock-up of what I'm trying to achieve follows:
Mock up http://www.claware.com/images/temp/mockup.png
Essentially, this part of the application attempts to parse words into syllables from tribal languages (no dictionary to refer to; any and all unicode characters are possible.) By the time the user gets this far, he has already defined the vowels / consonants in his language and some other configuration. There is then an iterative process of (1) the application guesses which syllables exist in the language based on some rules, (2) the user refines the guesses, selecting the correct parsings or manually parsing a word, (3) the application "learns" from the user's feedback and makes smarter guesses, (4) repeat until the data is "good enough" to move on.
The control needs to present each word (the grey headers), then all the syllable break guesses (the white areas with dots separating the parts of words.) There is also a way to manually enter a parsing, which will display a text area and save button (at the bottom of the mockup.) When the user hovers over a guess, the background changes and "accept / reject" buttons appear. Clicking on the accept, or entering a manual parsing, removes the entire word from the list. Clicking the reject button removes just that item.
I'm by no means 100% sold on the formatting I have above, but I think you can get a general idea of the types of formatting and functional control I need. The control will also scroll vertically--there may be thousands of words initially.
My question for you experienced WinForms developers is: where to start? I would really, really like to stay within the .Net core framework and extend an existing control as opposed to a third-party control. (At the risk of starting a religious war: yes, I suffer from NIH-syndrome, but it's a conscious decision based on a lot of quick-fix solutions but long-term problems with 3rd party controls.) Where can I get the most "bang for my bucK" and the least reinventing the wheel? ListView? ListBox? ScrollableControl? Do I need to go all the way back to Control and paint everything manually? I appreciate any help that could be provided!
[Edit] Thanks everyone for the ideas. It seems like the most elegant solution for my purposes is to create a custom control consisting of a FlowLayoutPanel and a VScrollBar. The FlowLayoutPanel can contain instances of the custom controls used for each word. But the FlowLayoutPanel is virtual, i.e. it only contains those instances which are visible (and some "just out of scroll"). The VScrollBar events determine what needs to be loaded. A bit of code to write, but isn't too bad and seems to work well.
I would look at the TableLayoutPanel and FlowLayoutPanel controls. These will let you organize a series of controls with moderate ease in a vertical fashion. I would then create a UserControl that consists of a label and 2 buttons. The UserControl will expose properties like Text and events that are exposed for the button clicks.. For each entry in the list, you will create an instance of the UserControl, assign the text value, and handle the click events. The instance will be placed in the Table/Flow panel in the correct order. Both of those layout panels do allow for inserting items between other items so you can add/remove items from the list dynamically.
Edit:
Given the length of what you are trying to render, I would consider using the DataGridView and do some custom rendering to make it perform how you want it to work. Using the rendering events of the DGV you can merge columns, change background colors (like highlighting the dark gray lines), turn on/off the buttons, and handle changing the grid into edit mode for your rows to allow modification or inserting of new values. This method would easily handle large datasets and you could bind directly to them very easily.
Well, this certainly looks like a candidate for a custom component that you should be creating yourself. You can create this using standard .Net drawing commands along with a text-box, and a regular button control.
Now you want to find out where to start.
Create a Windows Forms Control Library project.
Drop in the textbox and the button control.
The panel drawing code should preferably be done by code. This can be done using the regular GDI+ commands.
Edit:
Here's another idea, and one that I've practically used in my own project with great success.
You could use a web-browser control in the app, and show your data as html. You could update the source of the web-browser control based on the input in the textbox, and clicking on the links in the web browser control will give you the event that you can trap to do some action. Your CSS will work.
I used this technique to build the 'desktop' in an app I made called 'Correct Accounting Software'. People loved the desktop so much that it is one of the best loved features of the app.
Here's how I would do it:
Create a custom control. In this custom control, have a ListBox atop a LinkButton, and when the LinkButton is clicked you can make it give way to a TextBox. The ListBoxes will have the top row unselectable... you can probably get the rest from there. When you get your list of words, fill a Scrollable of some kind with one control for each word:
(foreach String word in words){
myScrollable.add(new MyComponent(word));
}
From there, I'm not sure what you want to do with the boxes or the data, but that's my initial idea on the UI setup.
Use the WebBrowser control and generate the HTML markup into it using DocumentStream or DocumentText.