Let's say that I want create a specialized wpf control, "YellowTextBox". It will be the same of a common TextBox, but it will be... yellow!. Ok, I go to code:
public class YellowTextBox: TextBox
{
}
Now, the obvious part, I want it be yellow...
this.Background = Brushes.Yellow;
Where I put that line of code? In the constructor? In OnInitialized override? OnLoaded, etc...
There are some correct (or better) place to put that line of code?
EDIT:
I know I can do it via styles, my question is more an "OOP" way of do it, it can be any other kind of property or field, not exactly Background Color, that selected property was just an example :/
You really ought to initialize a specialized WPF control in the initializers for the dependency properties (for properties it introduces), and in the default Style (for the new properties, and for anything it inherits that needs a different default value).
But you want to do it in C#, for some reason.
In that case, we're talking about a) OOP theology, b) OOP reality, and C) WPF mechanics. In terms of all of those, do it in the constructor, and in WPF, in the constructor after InitializeComponent() (if applicable, not in your case) is called. That'll precede any styles that get applied to the control in WPF, and it's good OOP practice and theology to initialize everything in the constructor that you didn't initialize in field initializers. A new instance of a class should be ready to go, in a consistent state that won't throw any exceptions if you start using it. So that means the initialization should be all complete at that point. Never leave any initialization to anybody else. That's a booby trap.
Do read up on InitializeComponent(), but in your specific case, the constructor for a subclass of a standard control, you won't be calling it.
A control subclass in WPF will apply styles after the constructor. It must! Before the constructor executes, it doesn't exist. "After the constructor" is basically all there is, aside from the guts of the constructor itself. You can override OnApplyTemplate() to hook into things immediately after the template is applied. But that's much too late to be initializing much (with the exception of private fields which will refer to template children).
So if you initialize stuff in the constructor(s), it gets applied to every instance, and if it's a WPF control class (or any FrameworkElement subclass), consumers of your class can override it by applying a Style or a template later on. That's good WPF practice: You want to allow people maximum scope to customize your controls.
Related
I have a .NET PropertyGrid control which displays properties of some class. I want to change the color or font or background color(it doesn't matter just that they look different from the other displayed properties) of some property. I can do with writing custom editor but I was wondering:
If an easier method exists?
If I use custom editor then how do i change the editor of built-in types like bool, int etc?
No can do. The class that determines how an item is drawn is PropertyGridView. The source code is interesting, it almost made it:
private /*protected virtual*/ PropertyGridView CreateGridView(IServiceProvider sp) {
return new PropertyGridView(sp, this);
}
Nope, looks like at the last minute they decided against making the method overridable. The PropertyGridView class was also marked internal. Replacing all this code (there is a lot of it) is not a realistic option.
Creating your own UITypeEditor for built-in types is only possible by applying the [Editor] attribute to the properties in the class you want to edit. That's not a general solution. Consider creating your own form to make the object editable instead.
I'm designing an user control and I'd like to make its behaviour configurable - but just once, when it's created. I don't need it to adapt later on, since I know beforehand that a specific window will to use it with a specific configuration.
Consider this simple markup:
<MyControl SomeProperty="True" SomeOtherProperty="12345" />
SomeProperty and SomeOtherProperty are DependencyProperties declared in my codebehind.
The issue is: The control does some preprocessing of its input data in its constructor, before InitializeComponent() is called. On that stage, I don't have the access to SomeProperty or SomeOtherProperty defined by the user - they still have the default values.
After that, if these properties are set in the XAML, they're assigned the values after the constructor. I can respond to them by introducing a PropertyChangedCallback and performing the calculations over again after each property is updated.
This is sub-optimal since I just want to pass the values once and make sure that the control's initialization logic is only ran once too - already with correct settings. The solution with PropertyChangedCallbacks requires me to make this control more complex, i.e. responsive to any changes to these dependency properties during the control's whole lifetime. This is much more than I need - it would be satisfactory for my properties to be read-only and set only once at the moment of control creation.
How can I manage to do that while keeping the XAML markup clean?
Your control must be constructed in order for WPF to set the properties - there is no way to "delay" the construction until after the properties are set.
Instead of putting your initialization logic in the constructor, you might want to try putting it elsewhere, such as subscribing to the Loaded event and initializing there. This will happen after the properties are set.
I've created an owner-draw user control that inherits from ComboBox.
The control stores specialized items, but the Items collection still accepts and returns items of type Object. Any tips on the best way to override this collection to be type-safe?
About the only way I can think of is to create my own collection class. The class wouldn't be a true collection--it would take an ObjectCollection as an argument to the constructor and simply extend the methods of that to.
The user control would pass the original Items collection to the constructor of the new class. And then override the Items property to return an instance of the new class instead.
This seems somewhat convoluted. Is there a better way?
You could do it a couple of different ways. First off, I'm a little confused about you creating a "user control" that inherits from ComboBox. You can create a custom control that inherits from ComboBox, but you cannot inherit from both UserControl (which is the usual definition of a "user control") and ComboBox.
If you define a true UserControl derivative, this gets a little easier. A UserControl, like I said, can't be a ComboBox, but it can have a ComboBox. So, you can drop and Dock a ComboBox to your UserControl surface, and then re-implement any properties you need to be able to use, such as Items. This will allow you to re-create Items as a collection of your choice, probably a strongly-typed List. The only problem will be knowing exactly what you'll want to re-implement; there's a lot of useful properties of a ComboBox that you won't be able to access in the Designer or in code unless you implement a "pass-through" property that modified the contained ComboBox within your UserControl.
If you inherit directly from ComboBox, it gets a little tricker in some ways, easier in others. You can hide the base class implementation of Items by defining your own and using the new keyword. You can change the visibility, type and other modifiers when you do this. This will prevent code that deals with your control as a CustomComboBox (or whatever you name it) from using the object array on the base class; they have to use your strongly-typed Items array. Your new property can still access the old one (which it will need to in order to make it work). You also get all the other public properties of a ComboBox for free; you only have to reimplement what you want to change. However, referring to your custom ComboBox as any base class will cause the runtime to use the version of Items that is valid for that class; that is, the object array, not your strongly-typed one.
I have a .NET PropertyGrid control which displays properties of some class. I want to change the color or font or background color(it doesn't matter just that they look different from the other displayed properties) of some property. I can do with writing custom editor but I was wondering:
If an easier method exists?
If I use custom editor then how do i change the editor of built-in types like bool, int etc?
No can do. The class that determines how an item is drawn is PropertyGridView. The source code is interesting, it almost made it:
private /*protected virtual*/ PropertyGridView CreateGridView(IServiceProvider sp) {
return new PropertyGridView(sp, this);
}
Nope, looks like at the last minute they decided against making the method overridable. The PropertyGridView class was also marked internal. Replacing all this code (there is a lot of it) is not a realistic option.
Creating your own UITypeEditor for built-in types is only possible by applying the [Editor] attribute to the properties in the class you want to edit. That's not a general solution. Consider creating your own form to make the object editable instead.
I want all labels inside a detail view to be bold. I created a simple custom label control that forces the font to be bold. This has the feeling of code smell to me. I'm not concerned with a developer being able to customize the custom control (baseDetailLabel). I just want to enforce an application wide standard for detail labels (They must be bold). Is it appropriate to force the font style when the control is initialized or should I be doing this in another method? I do want the style visible from the designer.
public class BaseDetailLabel : System.Windows.Forms.Label
{
public BaseDetailLabel()
{
System.Drawing.Font f = new Font(this.Font,FontStyle.Bold);
this.Font = f;
}
}
From the description I take it that you also have Labels that you don't want to be bold. In that case a separate Control class seems the best way to go.
The simple constructor approach will not prevent override, just sets an initial value. I think that is what you want. To force Bold you would have to override the OnPaint method.
About the smell: it isn't fancy but that comes with the territory. You're enforcing a style rule where there are no good (better) ways of attack. Unless you want to build an entire Style system.
This should be fine. However, I might caution you that you'll probably need to dispose the font somewhere. Fonts are graphical objects which need to be disposed - and I'm not sure if destruction of the label would automatically do that for you.