I'm trying to customize the look of a checkbox in WPF. I was hoping I could grab the default control template for the BulletChrome class that's defined in PresentationFramework.Aero and work with that. However, BulletChrome is not a sublcass of Control, so there's no template to modify. Does anyone know I could do this?
If you want to place some sort of BulletChrome in CheckBox' Template where the BulletDecorator in the classic Template would go, you could do that, since BulletChrome inherits from Decorator, which inherits from FrameworkElement.
The next part, how does the BulletChrome get its looks? Well, this is one of the rare parts from WPF where they handle rendering completely without xaml: The ButtonChrome's visual appearance is defined in its OnRender() method.
BulletChrome.OnRender(), from Reflector:
protected override void OnRender(DrawingContext drawingContext)
{
Rect bounds = new Rect(0.0, 0.0, base.ActualWidth, base.ActualHeight);
this.DrawBackground(drawingContext, ref bounds);
this.DrawDropShadows(drawingContext, ref bounds);
this.DrawBorder(drawingContext, ref bounds);
this.DrawInnerBorder(drawingContext, ref bounds);
}
Unfortunately, since all these methods called inside OnRender() are private, you can't mess with them even if you subclass the ButtonChrome, perhaps only overlay some of your rendering on top.
So basically, you either start digging through rendering code in Reflector and try to adapt and rewrite it to your needs, or roll your own Template/Decorator/whatever from scratch. (But then it really isn't important what you use as long as it works, right?)
Hope this answered your question, cheers.
You don't want to do this. Changing the control template is not supposed to change the behavior of the control, and a CheckBox control, by definition has three states (Checked, Unchecked, Indeterminate).
You're better off creating a custom 4-state (or n-state if you prefer) Control that borrows alot of Look/Feel from the CheckBox ControlTemplate.
If BulletChrome is not customisable, you can't customise it. But you definitely can replace it with something that is customisable.
In practical terms I would suggest starting with Silverlight's theme instead of Aero.
Related
Is it possible to keep a control (Panel) always over all other controls even if they also use Control.BringToFront()?
I tired to use BringToFront itself, but it seems that this loose its effectiveness if another control under this control also uses this command.
It would help if you try to explain what are you trying to achieve. We might be then able to better convince you, that you are doing something very wrong :)
Anyway, no matter what trick you do, the other control may use the same trick to override you.
You can get step ahead for example by handling parent control's Layout event to force your control back to front. The Layout event is trigerred (among other) when child controls' Z-order is changed.
private void Form1_Layout(object sender, LayoutEventArgs e)
{
panel1.BringToFront();
}
A dirty way of dealing with this is setting a timer and everytime it ticks use the .BringToFront() method on the control, you can also add multiple controls you wish to perform this on and can arrange them however you like.
I want to subclass the ListBox control and set the LBS_OWNERDRAWVARIABLE style. Subclassing is no problem and I can get messages through my own WndProc. (Actually I subclass the ListBox's parent in this case, as it is what is supposed to receive the WM_MEASUREITEM and WM_DRAWITEM messages). The problem is that I never get WM_MEASUREITEM or WM_DRAWITEM messages and the control continues to paint itself.
Both styles should be supported in WM5.0 and up:
WinCE3.0 supports neither: http://msdn.microsoft.com/en-us/library/ms959988.aspx
WinCE5.0 supports both: http://msdn.microsoft.com/en-us/library/aa453299.aspx
Even LBS_OWNERDRAWFIXED would be a start, but I can't get either to work.
My best guess is that the LBS_OWNERDRAWx style needs to be set at CreateWindowEx() time, as SetWindowLong() doesn't seem to change it. If that's the case, CF doesn't expose any methods that let me override window creation, and also doesn't expose anything like CreateParams (in full framework) or PreCreateWindow() that allows modifying the window-style before creation. (They're all there in the Control class but they're internal, so not accessible).
Has anyone managed to successfully do owner-drawing (even FIXED) using the actual Windows ListBox control on CF? Alternately, has anyone figured out a way to override the window-styles passed to CreateWindowEx() in a Control-based control? If so, please share your secrets :-)
Note: I do not want to create a list control from scratch; I can do that and there are various good examples of that out there, but that's not what this question is about.
CF2.0; WM6.1.
My application has a set of base classes derived from almost all the UI controls
XCombobox,XButton,XMenu etc. All these classes have some additional functionality apart from standard functionality (ex: Serialization capability)
I use all these controls in my test windows application.
I want to implement a concept similar to themes in my application.
Ex: Say if i need a blue background
I have a public property exposed in all controls which sets my controls
(i.e XButton and XMenu) backcolor to blue
I feel this approach is lame. Tomorrow if my manager wants some other styling.
I will have to go to every control and change the backcolor one by one ...not that i mind ;)....but this never makes me a good programmer.
Time for some application of a design pattern (strategy pattern shall i say ?)
Is there a possibility wherein i can just change in one central place and the property shall get applied to all of my UI controls ?
If yes... Please help me in realising the same.
If not ... Suggestions for some more better ideas are welcome.
Define a class that has properties for the colors (you can also add in properties for logos etc).
Then either have your constants in the code of that class, or read them in from some XML.
You answered your question already.
Define constants for styling in central properties, and use these styling constants in your UI components :).
I would use a dependency injection container such as Unity for this, it will allow you to register you theme in a single location and have all of your controls resolve the theme whenever they need it.
For example, implement a simple interface which has the properties of the theme that each control will use.
interface IXTheme {
Color BackColor { get; }
}
Wherever your control needs to fetch this, such as in OnPaintBackground, you make a simple call to fetch the color, using the CommonServiceLocator (This comes packaged with Unity already.)
protected override void OnPaintBackground(PaintEventArgs pevent)
{
Color backColor = ServiceLocator.Current.GetInstance<IXTheme>().BackColor;
///...
}
Now, you can create you theme somewhere else based on that interface.
class XBlueTheme : IXTheme {
Color IXTheme.BackColor { get { return Color.Blue; } }
}
You then register the theme with the container and use the container to resolve your form.
IUnityContainer container = new UnityContainer()
.RegisterType<IXTheme, XBlueTheme>();
IServiceLocator locator = new UnityServiceLocator(container);
ServiceLocator.SetLocatorProvider(() => locator);
XForm myForm = container.Resolve<XForm>();
From what you're saying, it seems like if you just want to change the color, the easiest thing would just be to save the color in a variable somewhere, or have some kind of initialization function that every component calls where you can specify shared things like the color.
Also, since you mentioned that you're adding additional functionality to components, you may want to use a Decorator design pattern for that purpose.
You can make something like .skin file provided in .net web projects. Or just an xml file will do; For instance,
Make a .skin file and add your controls and styling definitions there.
Add the .skin file path in some public property of your control's base class.
Add an event OnDraw, the all the controls override and color itself with the color defined in .skin.
Better try utilizing the existing .skin file; though I am not sure how would you plan to parse the .skin file.
<TextBox BackColor="Red" ForeColor="Blue"/>
<Button BackColor="White" ForeColor="Green"/>
<DropDownList BackColor="Cyan" ForeColor="Pink"/>
You can even extend the skin file by adding the cssClass property; and add styling according to css class defined in the css file.
<TextBox cssClass="TextLoginField"/>
<DropDownList cssClass="ComboLongList" />
Just thinking out loud! Btw, this article might give you an insight.
I guess the strategy pattern that you've mention fits the best.
That book Head Fisrt Design patterns describes this issue very well.
you need an interface say IStyle defined as a member of your base class so that the style behavior will be independent of your control inheritance.
I've seen two threads here about TDI & C#. Both of them didn't really answer the questions I have ...
Since TDIs are pretty much like a standard nowadays, I can hardly imagine, that I have to buy a special control (like AvalonDock or SandDock).
This must be possible with built in the tab-control(?) somehow! I don't need special features like dock- and draggable tabitems. Just open every form in a new tab. Thats it.
Like putting every forms content controls into user controls and by request (button, menu click ...) add a new tab and put the corresponding user control on it ... something like this.
How would you do it? This can't be THAT complicated (even for me) or am I missing something?!
thanks a lot!
Maybe Josh Smith's article on MVVM can give you an idea how to design such user interface. Example being built there is kinda tabbed document interface so you can use it as a starting block.
It's not that hard. It seems hard because there are a lot of different ways to do it.
Try this:
<TabControl x:Name="documentArea"/>
Handler for AddForm button:
private void AddFormClick(object sender, RoutedEventArgs e)
{
object form = GetNewForm();
documentArea.Items.Add(form);
}
That's it. You have to implement GetNewForm() in one of two ways. Have it return a user control that displays the form.
OR better yet, have it return your document that you want to display. Use a DataTemplate to select the controls to use for displaying this document. This method is going to be more complex to set up.
I am working on modifying a control on a existing site. All controls from the site inherit form a base class. I have a requirement to hide several links on the master page so I wrote this method on my control:
private void HideCartLink (bool visible)
{
Control control1 = Page.Master.FindControl( "link1" );
control1.Visible = visible;
Control control2 = Page.Master.FindControl( "link2" );
control2.Visible = visible;
}
I then moved on to another control and I had to do the same thing. So I refactored my code and modified my base class with this:
public void HideMasterPageControl (string controlName, bool visible)
{
Control control = Page.Master.FindControl( controlName );
control.Visible = visible;
}
and added this method on my controls:
void CartLinkVisible(bool visible)
{
////hide cart link
HideMasterPageControl("link1", visible);
HideMasterPageControl("link2", visible);
}
Now I moved on to a third control and realized I have to do the same thing.
Should I refactor my code one more time so that my base class has a method that knows specifically which links to hide? Or should I leave my base class generic and let my controls decided what to hide?
I am not sure what the rule is here...
If I'm honest, I'd be more inclined to turn this upside-down. I'd have something that added the buttons/links as necessary, based on the criteria of the page. This would then give you something more like a toolbar, and in fact you could make it configurable (or based on user privileges) which buttons/links appear on each page.
This saves you from the awkward position of working out on what basis to hide things that may or may not even be there.
Of course, assuming you can't do this, you're probably making the best of a bad job to be honest. Don't worry too much further about the about the final implementation. With only a few controls you're okay and would be making it worse by over-complicating it.
You might want to consider the Visitor pattern, though. This would mean you implement a class that "visits" all the links on a given control and goes to configuration to look up whether they should be hidden or not. This would save you hardcoding the control names for the links, and allow the method to be in a base class that has no idea what actual controls there are.
I'd have a generic base method that would call a virtual method to get a list of links to hide and cycle through them. The base implementation of the second method would contain the list of most commonly hidden links. Each control I'd just overwrite the method to add or modify that list.
Though, I have to agree with Neil, it seems better if you flip the logic and decide which links need to be included vs. which need to be excluded.