Owner-Drawn ToolStripDropDownButton - c#

I'm writing some custom behavior for a ToolStripDropDown control. I'd also like to modify the ToolStripDropDownButton itself to display a colored shape.
I see that I can handle the Paint event and draw whatever I like. However, is there any way to have the button paint the default background before I paint the shape? It would be hard to get the background exactly right, especially with future versions of .NET and Windows.
In plain ol' Windows, I could invoke the default proc handler before or after my paint code. I'm not seeing any way to accomplish that in .NET. Or perhaps there's a way to tell the button to paint only the background?

When you handle the Paint event (as opposed to overriding the OnPaint method in a derived class) the base class (default proc handler) is already getting called. Everything gets drawn as normal, and then you're essentially drawing on top of that in the Paint event. You can see that clearly here:
The trick is making sure that you leave enough of the control's clipping rectangle exposed to show the part you want. The e.ClipRectangle property retrieves the entire button's client area, so if you just
fill that with a color swatch, you're going to cover up the drop-down arrow and default background, too. The above demonstration was created using the following ugly sample code:
private void ToolStripDropDownButton1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.FillRectangle(Brushes.Chartreuse,
e.ClipRectangle.X + 3, e.ClipRectangle.Y + 3,
e.ClipRectangle.Width - 12,
e.ClipRectangle.Height - 12);
}
Other than that, I don't think there's a way to customize what exactly gets drawn by the base class. Owner-drawing (at least in WinForms) tends to be an all-or-nothing affair. You get complete control,
but it comes at the price of having to implement everything yourself.
Of course, in case you haven't already noticed, the ToolStrip control already doesn't look like a native Windows control. And even worse, it is always going to look exactly the same as it does now,
even in future versions of Windows that completely overhaul the UI. (The MenuStrip is plagued by
this same phenomenon, and the difference is very visible in Windows Vista/7 where the standard API menus have changed dramatically). The reason is that both controls are drawn entirely in C# code written in their WinForms implementations. Personally, I think it looks ridiculously cheesy, and wouldn't use it in one of my applications on a bet.
You can assign a custom renderer that uses the UxTheme API to draw the buttons, which will get much closer to approximating the look of the native menus and toolbars. A pretty thorough sample is available here. I've written something very similar for the WinForms development that I've done requiring the additional features of the ToolStrip class (such as embedding combo boxes) not offered by the
old-school MainMenu and ToolBar controls that simply wrap their Windows API equivalents. By choosing to do things this way, you do have more control over exactly what parts of the base class renderer you wish to call, as you've written the code explicitly yourself. Highly recommended if you're
the type that cares at all about UI, native feel, or user experience.

Related

Custom cursor above every other visual component

I have a Windows Modern App with a custom cursor, that is implemented by having an image that follows the system's cursor.
I just add the custom cursor image to the main grid of my application and everything works fine.
public MainPage() : base(true)
{
this.InitializeComponent();
MainPageGrid.Children.Add(new CustomCursor());
}
But when a popup opens, it gets above my custom cursor. Is there anyway that I can set the Z-index (or something similar) of a component in order for it to be the uppermost visual component of my modern application?
I would recommend using an actual custom cursor. I think this article looks like a decent intro to using these. You could also check this question for some tips on changing cursors. Other than that - I don't think you can tell when a random popup opens. You can poll for these with VisualTreeHelper.GetOpenPopups(), and then do something to make your popup show on top (maybe just reopening would work or maybe you'd need to create a new one every time) but that might not give you a good user experience or performance. You could also figure out all the events that could display a popup from ComboBoxes, Flyouts etc, but that sounds painful. It would probably be best to create an attached behavior that you could attach to all such popup-source-elements to trigger z-index fix-ups of your XAML-rendered custom cursor...
There is no need to implement a component as a custom cursor, as it is possible to override the maximum size limitation:
How to override maximum 32x32 mouse size in Windows like this program can

Remove left and right side borders

I want my TextBox to look like this
How can I remove the left and right sides of my TextBox control?
Normally, you'd have to override the OnPaint event to do this, for a Textbox however, this will not work because OnPaint wont get called.
An approach would be to subclass TextBox as described here
However I wouldnt suggest you to do this at all, it sounds like a daunting task to me (never did this myself), espacially when you are new to programming.
Maybe it would suffice to just draw a line above or beneath the TextBox?
-edit-
Maybe this will explain it better:
The TextBox is special in that you can't custom paint it.
If you just want a custom border, you can create a new UserControl and add a TextBox with border style set to None. Make sure you leave enough room around the outside of the TextBox for a border. Then paint the border on the UserControl surface.
An alternative method would be to handle the WM_NCPAINT message of the TextBox and paint the border then, but that is significantly more complicated.
Source: shawn.ohern in msdn forums: here
(Sorry I didnt know how to link to his post directly)
-edit2-
This link shows a way to create your own TextBox, which, again, I would not recommend to someone who is new to c# and programming ;)
Windows Forms is based on Win32 API which, unlike WPF which uses declarative language for describing UI, gives you full control of painting your own control.
Take a look here: Custom Control Painting and Rendering.

Drawing Custom Control above all other controls (previously added)

I have a UserControl that adds other UserControls, but I want the "latest" control added to be topmost so it's above the others. Because the controls should be overlapping eachother. Like a card game. So I add 5 controls, the first one should have the least priority the latest the most priority - most visible.
Any ideas?
Or do I have to override the Paint method for the "container" control? And Control.CreateGraphics() and draw it?
Consider BringToFront and SendToBack methods of the Control class.
Check out answers to these questions too
How to set Z-order of a Control using WinForms
Bring Winforms control to front
Just use userControl1.BringToFront() when you add the new control.
Note however, that won't prevent the user from "tabbing" into the controls that are underneath it. For that, you need to disable or make invisible the other controls.
In Windows Forms, the order in which controls are added to their parents' Controls collection determines the order of their rendering.
This means that either you handle the addition of child controls in code and use the appropriate insert positions, or you move the controls around in the designer (which, unfortunately, often means dangerous hand edits to the *.Designer.cs file).
I recommend that you go for the first approach, which is the only feasible method for larger WinForms projects anyway, and make the control insertion logic explicit in your code. The good news, by the way, is that there is no need to tinker with paint handlers, so your worry about hacks like using CreateGraphics() is unjustified and dispelled :)

Windows aero glass form text problem

I use windows form with GlassForm(using Microsoft.WindowsAPICodePack.Shell;). my problem when I change form to GlassForm my textbox texts doesnt
Place a panel on the form set the dock style to fill, set the panel's BackColor to color X and then set the form's TransparencyKey to the same color X.
Yes, that's how it works. With the Aero Glass effect applied, anything drawn in the color black will be rendered as transparent. That includes text in a textbox control. This general theme has been the subject of many other questions here. When well-written, they gather lots of upvotes, but few answers.
There just aren't a lot of good solutions here. All of them that I've come across qualify as both "ugly" and "hackish". Owner-drawing is a reasonable approach when you're using something like a label control, but I wouldn't recommend trying to draw your own textbox—it's just too hard to get right. Someone tried to do that here; like I said, the result is both ugly and hackish. I wasn't satisfied with it for my own use, but it may work for you, depending on how high your standards are.
The goal with owner-drawing, of course, is either to do all of the drawing using GDI+ (which natively supports transparency) instead of GDI (which all of the built-in controls use by default), or calling functions like DrawThemeTextEx, which is specifically designed for rendering text with a shadow that is [somewhat] readable over glass.
As well, the usual tricks like enabling compatible text rendering (which causes the built-in controls to draw using GDI+ routines, as they did in the early versions of .NET) don't work for a textbox.
Honestly, your best bet is to place the textbox over a region of your form that is not rendered as glass. Use the DwmEnableBlurBehindWindow function to selectively enable the glass effect behind certain areas of your form, rather than the entire thing. I provide a complete, ready-to-use .NET implementation in my answer here.
Check this sample out:
http://www.danielmoth.com/Blog/Glass-In-C-An-Alternative-Approach.aspx
I was not studying it any further but putting a TextBox or Button or other components over this Aero glass area worked - the rendered component didn't have the transparency problem. The labels aren't perfect but these can be easily drawn with GDI+
The direct link to the sample project is here: http://www.danielmoth.com/Blog/MothGlass.zip
It looks like he puts a panel behind the control and setting the TransparencyKey for the panel.

Winforms: creating a dynamic timeline control

I need to create a winforms control what looks something like this:
Currently i'm considering taking a picturebox/panel and overriding onpaint event and drawing all the stuff myself. But somehow this approach doesn't seem right.
I was wondering maybe there's an easier way out or perhaps a better solution?
How would you make a control like this?
No, that is the right way to do it. Trying to use something like a TableLayoutPanel is not only excruciatingly painful, it also sucks serious mud taking a second or more to paint itself. It will take a bunch of code, but it isn't hard code. Plenty of for loop opportunities as well.
Get the scrolling view with panel's AutoScrollMinSize. Use Graphics.TranslateTransform() passing AutoScrollPosition in the Paint event or OnPaint override. The latter is recommended, derive your own control from Panel to keep the code separate. You have lots of flexibility here to customize the appearance, have fun.
The last time I did something like this I did the grid as a bitmap, loaded the image into a picture box, and drew directly on the image. The problem with using the paint event it's not persistent with minimizing etc unless you keep redrawing it.
It would probably be easier to override a literal control or inherit from the CompositeControl class and then render it with HTML (tables) and Javascript as opposed to drawing it.

Categories