Highlighting text in a Winforms textbox - winforms

For a Winforms textbox, when you click and drag over the text, it highlights it. Is there a way to determine which direction the user dragged over?

There is no way to get this info using the Windows TextBox selection API. For example, the EM_GETSEL message defines the starting and ending character positions of the selection, but in a predefined (sorted) order.
However you could get this info by handling the control's MouseMove event. For example:
textBox1.MouseMove += new MouseEventHandler(textBox1_MouseMove);
void textBox1_MouseMove(object sender, MouseEventArgs e)
{
Control tbCtrl = sender as Control;
// the mouse coordinate values here are relative to the coordinates of the control that raised the event
int mouseX = e.X;
...
}
By applying some logic to mouseX you could potentially discover the average direction the cursor is moving. It would work best if the user is making a linear motion. You could also handle the textbox's drag-and-drop event for similar mouse information if you only wanted the event raised while the user was dragging the mouse.

Related

How to implement my own scrolling in windows form

I have an MdiClient derived from Form and I use the surface of this control for GDI+ drawing. I run into troubles implementing my own scrolling for this control. I set both AutoScroll and AutoSize properties to false and try to use form's own horizontal/vertical scrollbars instead of placing my own. Observed form's behavior is quite confusing. To begin with there are two properties (A) HScroll and (B) HorizontalScroll that also allows access to Visible attribute.
I ended up setting HorizontalScroll.Visible = true and leaving HScroll = false (same for vertical) but am curious why there are two of them. Documentation implies that both control visibility of horizontal scroll bar but they do not appear to access the same data. Besides, it looks like HScroll is being reset on every paint. At the moment I ignore existence of HScroll/VScroll. Is it OK for my application?
What is more critical for me is the ability control placement of the thumb on scroll bars. I set VerticalScroll attributes Minimum = 0, Maximum = 100, and Value = 50 but when form is displayed thumb is positioned at the start of scrollbar not in the middle. Why? Also when user clicks on horizontal scrollbar an event handler for horizontal scrolling is invoked but meanwhile form has already reset VerticalScroll.Value to 0 (without raising vertical scroll event). What is going on?
I probably don't understand how framework expects me to implement what I need. Can someone shed some light.
Credit goes to LarsTech who pointed me towards good solution. Setting large AutoScrollMinSize automatically does whatever needs to be done enabling and controlling form scrollbars. There is one potential trap to watch for. Be aware that programmatic attempts to set AutoScrollPosition will be ignored until form is shown. So if you want your form to open with scrollbars not in the default (0,0) position then place your code inside form_shown event handler.
Just set the AutoScrollMinSize to your desired canvas.
Quick example:
using System.Drawing;
using System.Drawing.Drawing2D;
private void Form1_Load(object sender, EventArgs e)
{
this.AutoScrollMinSize = new Size(1200, 1200);
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(SystemColors.Window);
using (Matrix mx = new Matrix(1, 0, 0, 1, this.AutoScrollPosition.X, this.AutoScrollPosition.Y))
{
e.Graphics.Transform = mx;
e.Graphics.FillEllipse(Brushes.Red, new Rectangle(250, 250, 100, 100));
}
}
See these links: Understanding Windows Forms AutoScroll and How to back-track the mouse to the virtual page.

Silverlight. Fix needed. Dragging stack panel item to the right moves it underneath other items

I have stack panel with custom controls in it. I attach standard MouseDragElementBehavior to each item.
When I drag to the right the item moves underneath the other items.
What would be a viable solution to create better user experience - to show better visual cue - how the item moves and where is it going to be dropped.
After a bit of tinkering I realised that nothing can be dragged within stack panel to the right not being coverd by other elements .. unless you drag the very right item..
What I did to resolve it:
Created a visual cue (half transparent shape of a generic item to represnt it during the drag operation)
Made the cue invisible (width=0) and keep it always as the very last element of the stack panel children
Subscribed the stack panel to mouse left button up, down, move
Emulated drag/drop with code
Once the drag initated I turn the cue to visible and set its translate transform to the current mouse coordinates
Adjust translate transform on every mouse move event
On drop I hide the cue again and rearrange items in a way I want.
To stress again - whatever way you do - you have to manipulate with the last element in StackPanel.Children collection....
If the MouseDragElementBehavior doesn't work the way you need it to, you could always descend from the class and customize it to your needs. For example:
public class DragBehvaior : MouseDragElementBehavior
{
public DragBehvaior()
{
this.DragBegun += new MouseEventHandler(DragBehvaior_DragBegun);
}
void DragBehvaior_DragBegun(object sender, MouseEventArgs e)
{
var element = this.AssociatedObject as UIElement;
// Calculate the correct ZIndex here.
Canvas.SetZIndex(element, 100);
}
}

Making a moveable control in WPF

I have a panel, within that panel are several rectangular controls (the number of controls vaires) I want the user to be able to move the controls around within the panel so that they can arrange the controls in the way that suits them best. does anyone have any resources i could read or simple tips which would get me headed down the right road?
thanks
I figured out a possible, simple method of moving a control in a drag/move style... Here are the steps.
Select an element in your control which you wish to be the movement area. This is the area in which, if me user holds the mouse down, the control will move. In my case it was a rectangular border at the top of the control.
Use the OnMouseDown event to set a boolean (in my case IsMoving) to true and the MouseUp event to set it to false
On the first MouseDown event, set some Point property (InitialPosition) using the following code
if (FirstClick)
{
GeneralTransform transform = this.TransformToAncestor(this.Parent as Visual);
Point StartPoint = transform.Transform(new Point(0, 0));
StartX = StartPoint.X;
StartY = StartPoint.Y;
FirstClick = false;
}
Now that you have the starting position, you need to get the position of the mouse relative to your movement control. This is so you dont end up clicking the middle of your header to move it and it instantly moves the top left of the control to the mouse pointer location. To do this, place this code in the MouseDown event:
Point RelativeMousePoint = Mouse.GetPosition(Header);
RelativeX = RelativeMousePoint.X;
RelativeY = RelativeMousePoint.Y;
Now you have the point the control originated at (startX and STartY), the position of the mouse within your movement control (RelativeX, RelativeY), we just need to move the control to a new location! There are a few steps involved in doing this. Firstly your control needs to have a RenderTransform which is a TranslateTransform. If you dont want to set this in XAML, feel free to set it using this.RenderTransform = new TranslateTransform.
Now we need to set the X and Y coordinates on the RenderTransform so that the control will move to a new location. The following code accomplishes this
private void Header_MouseMove(object sender, MouseEventArgs e)
{
if (IsMoving)
{
//Get the position of the mouse relative to the controls parent
Point MousePoint = Mouse.GetPosition(this.Parent as IInputElement );
//set the distance from the original position
this.DistanceFromStartX= MousePoint.X - StartX - RelativeX ;
this.DistanceFromStartY= MousePoint.Y - StartY - RelativeY;
//Set the X and Y coordinates of the RenderTransform to be the Distance from original position. This will move the control
TranslateTransform MoveTransform = base.RenderTransform as TranslateTransform;
MoveTransform.X = this.DistanceFromStartX;
MoveTransform.Y = this.DistanceFromStartY;
}
}
As you can guess, there is a bit of code left off(variable declarations etc) but this should be all you need to get you started :) happy coding.
EDIT:
One problem you may encounter is that this allows you to move the control out of the area of its parent control. Here is some quick and dirty code to fix that issue...
if ((MousePoint.X + this.Width - RelativeX > Parent.ActualWidth) ||
MousePoint.Y + this.Height - RelativeY > Parent.ActualHeight ||
MousePoint.X - RelativeX < 0 ||
MousePoint.Y - RelativeY < 0)
{
IsMoving = false;
return;
}
Place this code in your MouseMove event before the actual movement takes place. This will check if the control is trying to move outside the bounds of the parent control. The IsMoving = false command will cause the control to exit movement mode. This means that the user will need to click the movement area again to try to move the control as it will have stopped at the boundary. If you want the control to automatically continue movement, just take that line out and the control will jump back onto the cursor as soon as it is back in a legal area.
You can find a lot of inspiration here:
http://www.codeproject.com/KB/WPF/WPFDiagramDesigner_Part1.aspx
http://www.codeproject.com/KB/WPF/WPFDiagramDesigner_Part2.aspx
http://www.codeproject.com/KB/WPF/WPFDiagramDesigner_Part3.aspx
http://www.codeproject.com/KB/WPF/WPFDiagramDesigner_Part4.aspx

wpf: capturing mouse does not work

I am developing an kind of outlook calendar application where I need to make the appointment resizable from mouse.
My first try with a thumb did not work properly so I tried another way.
What I did is that:
1) on the botton of the appointmennt panel I added a rectangle to figure out the resize zone (the thumb). The appointment panel is put on a grid panel.
2) I intercept down event on the rectangle and send event to this code:
private Point startPoint;
private void OnResizeElementMouseDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
this.MouseMove += new MouseEventHandler(ResizeEndElement_MouseMove);
this.MouseLeftButtonUp += new MouseButtonEventHandler(OnResizeElementMouseUp);
// some code to perform new height computation
Mouse.Capture(this);
}
where this is the appointment panel that own the thumb.
Decreasing height works well.
But increasing is more difficult. If I move the mouse very very slowly it's OK, if I speed it up a little bit it tends to leave out the appointment panel and then all MouseMove event are lost.
I thought Mouse.Capture() was propose to solve this kind of problem, but in fact not.
Does anybody know what is wrong in my code?
You should be using an actual Thumb control. Check out MSDN for help:
How to: Use a Thumb to Enable Dragging
you should use a thumb, but to play with mouse capture, override the protected override void OnLostMouseCapture(MouseEventArgs e) method, then you will know if you have lost the capture.

WPF - simulate mouse events on off-screen rendered Grid

I'm rendering a WPF grid with multiple elements (buttons, textbox, ...) to a bitmap which is then used as a texture for a 3D surface in a Direct3D scene. For user interaction I create a 3D ray from the 2D mouse cursor position into the 3D scene finding the intersection point with the gui surface. So I know where the user has clicked on the WPF grid, but from there I'm stuck:
How can I simulate mouse events on the WPF elements while they are not actually shown in an open window but rendered off-screen?
Recently, I was looking into UIAutomation and RaiseEvent but these are used to send events to individual elements, not the whole visual tree. Traversing the tree manually and looking for elements at the cursor position would be an option but I haven't found a way to do this accurately. VisualTreeHelper.HitTest is a good start but instead of finding TextBox it finds TextBoxView and instead of ListBox it finds a Border.
EDIT: returning HitTestResultBehavior.Continue in the result callback of HitTest lets me walk through all elements at a given point. I can now send mouse events to all these elements but the values of the MouseEventArgs object are those of the real mouse. So I have to create a custom MouseDevice which apparently is impossible.
PointHitTestParameters p = new PointHitTestParameters(new Point(
((Vector2)hit).X * sourceElement.ActualWidth,
(1 - ((Vector2)hit).Y) * sourceElement.ActualHeight));
VisualTreeHelper.HitTest(sourceElement,
new HitTestFilterCallback(delegate(DependencyObject o)
{
return HitTestFilterBehavior.Continue;
}),
new HitTestResultCallback(delegate(HitTestResult r)
{
UIElement el = r.VisualHit as UIElement;
if (el != null)
{
MouseButtonEventArgs e = new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left);
if (leftMouseDown) e.RoutedEvent = Mouse.MouseDownEvent;
else e.RoutedEvent = Mouse.MouseUpEvent;
el.RaiseEvent(e);
}
return HitTestResultBehavior.Continue;
}), p);
You might be able to send windows messages (like WM_MOUSEMOVE) to the WPF window's HWND, via the PostMessage(..) win32 method. I believe these messages would be read by WPF and executed as if it came from a user.
If you are feeling really brave, you can try my hack to get access to the WPF IDirect3DDevice9Ex. From there you can copy the backbuffer in the swapshchain to your d3d scene. If you are using 9Ex (Vista D3D9), you can take advantage of the shared resources (share surfaces/textures/etc between devices and processes) feature to help with performance.
You may still have to do some trickery with windows messages for interactivity.

Resources