Can my RoutedEvents arguments validly have settable parameters (like RoutedEventArgs.Handled)? - c#

My WPF Custom Control handles dragging shapes across an image on a canvas. Some shapes may be dragged beyond the limits of the image but others should be limited. But the control itself does not know the rules, only clients (i.e. the XAML page that created the control or its View-model) knows what they are.
So I need to give this control a way to let clients know that shapes are about to be dragged so that clients may limit drag for the duration of the drag operation
I had the idea for a RoutedEvent (e.g. ItemDragStarting) that my control could raise when shape dragging begins. I reasoned that we already know that event handlers traditionally set the RoutedEventArgs.Handled property to stop further processing of the event. That seems basically like an "OUT" parameter doesn't it?
So maybe my RoutedEventArgs object of my ItemDragStarting event could expose a "ValidLimitRect" parameter to allow clients to optionally set the valid limits. After the event fired, the control could check this and, if set, limit the drag for this one drag operation.
For example:
// User has started dragging items. Raise the event with no limit rect
var args = new DragStartingEventArgs(itemsBeingDragged, Rect.Empty);
RaiseEvent(args)
// Did any of the clients set the limit rect to anything?
if (!args.LimitRect.IsEmpty)
{
// Save the value to limit dragging
}
But I've never before made event-firing code actually care about the end state of its arguments. Until now they've always been fire-and-forget. So I am wondering if this is even a good idea.
Is this anything resembling standard practice in WPF or is this code-smell? If it is the latter, what's the better way to do this?

Related

Trackbar with a level indicator inside the track?

I was wondering if there is a way to setup a level indicator inside the track of the .NET TrackBar?
My usage scenario is this. I need an audio squelch control. So I want to use a TrackBar where the user drags between 0 and 100 squelch. But at the same time I want to show the current audio level in the track of the TrackBar. So that the user knows where the current audio level is relation to the squelch.
Any suggestions? Is this something were I need to override the paint method of the TrackBar? Or is there a free control somewhere I could use?
This will not be as easy as it might seem. One cannot simply augment the appearance of the TrackBar control. You have to trigger UserPaint by adding the following line to the constructor of a class that derives from TrackBar:
SetStyle(ControlStyles.UserPaint, true);
This will, however, force you to own all of the painting. Meaning that you will then need to override both OnPaint and OnPaintBackground and use the methods in TrackBarRenderer to paint the entire control.
Having said that, the methods given to you are pretty straightforward, and drawing the control is relatively easy.
Note: this Code Project article is bound to have lots of good pointers if you decide to pursue full-on custom drawing. Perhaps could even serve as your replacement control.
There are others. Just do a Google search for "C# TrackBar custom draw".

How to make custom shaped panel in WPF?

I am facing a problem that have kind of already been asked here before, as far as I have seen.
I read most of these but didn't find the right answer.
This is what I need:
Complex shaped zone (i.e: countries, states..)
Having possibility to get events on it (especially mouse's)
Possibility to place some conrols in it (i.e: images, buttons)
I saw that some uses usercontrols, controltemplates.. But how should I do for that kind of shape ? Most of questions was for some basic mix of standard shapes.
(I saw with Blend that we can make path object with a pen, is there a way to use this to define the shape of a zone ?)
Thanks.
Create your own control and have its main container be a Canvas. Have the canvas background be transparent and then you can place all the controls you want on it. You can use a Polygon as your main shape inside the Canvas and place all the controls you want on the Canvas (but I guess for your purpose, you would want to make sure to not place them outside of the area covered by the polygon.
Let each object you use handle the mousedown event then you can individually drag them. When mousedown occurs, use the CaptureMouse() method on the object you clicked so that all dragging (on or off of the main window) will still be captured by the object you clicked. Make sure to call ReleaseMouse() in the mouseup event.
You can create as many instances of your control as you need. All with different shapes defined by the polygon each one contains. You can slap all of these objects on a single grid or canvas, and you're good to go.
You can use the PathPanel class that is provided in the Expression Blend SDK.
More information here

Inject/simulate WPF routed mouse click events

I have some straight WPF 3.5 controls handling left mouse clicks that I need to use within a Surface app (SDK 1.0). The problem I am facing is that do not work by default. I am thinking of wrapping each control in a SurfaceContentControl and translating ContactTouchDown or ContactTapGesture events to corresponding MouseDown events.
The problem boils down to - how to "inject" or simulate arbitrary routed mouse events? I have tried InputManager.Current.ProcessInput() but didn't get very far. Any help is appreciated.
Try to use AutomationPeer classes. For example ButtonAutomationPeer is for Button. The code below initiates a click.
ButtonAutomationPeer peer = new ButtonAutomationPeer(button);
IInvokeProvider provider = (IInvokeProvider)peer.GetPattern(PatternInterface.Invoke);
provider.Invoke();
evpo's idea is an interesting one (though if you're working with custom controls, they rarely come with AutomationPeer classes).
You can't simply 'inject' mouse input by sending WM_MOUSE* events to your app... WPF would indeed process the message but when it goes to figure out the position of mouse for that event, it will query the actual mouse API instead of trying what you stick in the WM.
So really all you can do is tell windows to move the actual mouse cursor and act as though the button is being clicked/released. Some code you can use for that is in http://www.codeproject.com/KB/system/globalmousekeyboardlib.aspx
That said, while you can technically do this, it sucks... you've got an expensive multitouch device but are 1) showing a mouse cursor on it 2) limiting arbitrary parts of it to being used 'single touch' (and only one of those arbitrary parts at a time and 3) coming up with an arbitrary method of determining which finger you will treat as the mouse-controlling one

How can I write my own ContextMenu? C#

I feel quite limited by the default ContextMenuStrip, as it only can contain buttons, and no Controls.
I was wondering that for a long time, and I already tried it, using forms, but it never really worked out.
I already have I idea on how to set the whole thing up, with events and items. The only problem I have is the paint method.
When you open a ContextMenu (ContextMenuStrip) you can set its position on the mouse cursor, and it will be there, even if that means that it goes beyond the active form. (So I can't use the Controls Class as inheritance, as they can only draw themself as a part of a form.
Now I thought to use the Form Class as a base for my ContextMenu, but those where placed on the screen randomly.
So what I actually need is a class (or something similar) that can draw itself, without problems, and can be placed accurately on the screen.
Any hint would be nice, thanks.
Greg the Mad
Your first statement is false -- you can have a TextBox or a ComboBox in a ContextMenuStrip.
MSDN ToolStripComboBox
MSDN ToolStripTextBox
From the designer there is a small drop-down arrow when your mouse is in the "Type Here" box (sometimes hard to click) that will allow you to change the type.
If you are looking to allow for any type of control to be displayed in a top down fashion inside of a container to be positionable... you could always make a custom control using FlowLayoutPanel. With it's properties FlowDirection=TopDown and WrapContents=False to keep a vertical approach. This will handle your "menu" basics and your new control can expose whichever events you wish from each Control. You will have to handle the logic of showing the panel and positioning with it's Location property as well.
I forgot to address the issue with drawing outside of the parent form. Notice that ContextMenus are smart and when they reach a boundary of their parent they draw away from it. You should logically be able to draw in the correct direction (Up/Down or Left/Right) from any right mouse click. Per your attempt with a Form, set StartPosition=Manual then prior to calling Show() or ShowDialog() set it's Location property respective to the X and Y parameters provided in the event args of MouseClick.

How do I determine when to show a tooltip?

I'm writing a calendar control in .Net WinForms that will show a tooltip for each date.
What's the best way to determine when to show the tooltip?
Showing it immediately in MouseMove would make it get in the way, so I'd like it to show when the mouse hovers over each date cell.
The MouseHover event only fires on the first hover after MouseEnter, so I can't use it.
What's the best way to do this?
EDIT:I'm using WinForms
The time delay between Enter and Hover is specified in SystemInformation.MouseHoverTime.
If for some reason the built-in tooltip handling code for whichever UI framework you're using isn't sufficient, you could just spin up a Timer after each MouseMove and show a Tooltip when it fires. Obviously, you'd need to reset the Timer each time the mouse is moved to prevent a long series "rain of tooltips".
It would be helpful to know which technology you are using (ASP.NET? Forms? WPF?) because they all have different ways of implementing tooltips:
With ASP.NET, you can simply set the
ToolTip property of a control (such
as a Label control that shows a number in your calendar), and it
will automatically show a tooltip
after a slight delay when hovering
over the control.
In Forms, I think you have to
actually create a ToolTip object then
attach a control to it.
In WPF, you can add a Label.ToolTip
element to your XAML code.
In all cases, though, there's a built-in way to do it, so it might not be necessary for you to write your own code at all.
If your situation is so custom that you do need to write your own code, I'd really need to know more about how you are representing the numbers in your calendar to help you out.
Last thing: you didn't really ask this--and it may not be under your control--but you might want to ask yourself whether a tooltip is the best way to show calendar information in the first place. If space is really tight, then the answer might be "yes", but if you have enough space to show the calendar events (or even the first few words of each event), this would save the user from having to "scrub the whole calendar" (i.e., roll over each date individually).
-Dan
Have a look at the AutoPopDelay, InitialDelay and ReshowDelay properties of the ToolTip class, as they control the behaviour of the tooltip.
I generally play around with the values until I get something that 'feels' right. It's annoying when a tooltip shows immediately, and for short tooltips, it's also annoying when they disappear too soon. For really long tooltips, say, several paragraphs (yes, poor design decision, but if there's a lot of info to read, at least let me read it!) then it should stay open as long as my mouse is stationary.
A tooltip example from MSDN gives the following values:
AutoPopDelay = 5000;
InitialDelay = 1000;
ReshowDelay = 500;
// Force the ToolTip text to be displayed whether or not the form is active.
ShowAlways = true;
As mentioned in a comment, the poster wants to trigger the tooltip programatically. For that, ToolTip.Show( ) needs to be called. To get a delay effect, you'll likely want to have a timer running which counts the time that the mouse is stationary. Whenever the mouse enters, leaves or moves within the control, this time should be reset.

Categories

Resources