Drag and drop a popup text box in WPF - c#

I have created a little program in WPF where I click on a button and a popup text box arrive. I would like to make this movable - drag and drop.
In the code I have created an object for a textbox named x, and used the command x.AllowDrop = true;, but without success.
I have tried MSN, Youtube and other sources, but without success.
private void button1_Click_1(object sender, RoutedEventArgs e) {
TextBox x = new TextBox();
x.Name = "new_textboxqq";
x.TextWrapping = TextWrapping.Wrap;
x.Text = "asfsadfasfsadfasff";
x.VerticalScrollBarVisibility = ScrollBarVisibility.Visible;
x.Background = Brushes.Yellow;
x.AcceptsReturn = true
x.Margin = new Thickness(5, 10, 0, 0);
x.AllowDrop = true;
HouseCanvas.Children.Add(x);
this.AllowDrop = true;
Canvas.SetLeft(x, 20);
Canvas.SetTop(x, 20);
}

Drag and Drop is a data transfer technique. From one control or files to another control or window.
If you need to move your control inside window, you need using mouse events: MouseDown, MouseUp, MouseMove. Look this.

You want to drag a TextBox and move it around on a Canvas, but AllowDrop property is for Drag-and-Drop operation. Drag-and-Move and Drag-and-Drop are different operations.
This is an example to do what you want.
The idea is handling the MouseMove event of the Canvas, calculating the position of the mouse cursor, and by setting the position of the TextBox to that position, you can make the TextBox move following the mouse cursor.

Related

C# - Why is my dynamic label not transparent even if the parent is set?

I am writing a WinForms application. In this application I generate dynamic Label, PictureBox and TextBox controls.
With dragging and dropping an Image into the PictureBox , the added TextBox opens. With entering some text and pressing 'Enter' the following method is fired.
private void tb_Tile_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
TextBox tb_Tile = sender as TextBox;
Tile tb_Tag = tb_Tile.Tag as Tile;
//add function that overgives the given name to the matrix i.e. GiveNameToMatrix()
tb_Tile.Visible = false;
Label lbl_Tile = Controls.Find("Label" + tb_Tag.X + tb_Tag.Y, true).FirstOrDefault() as Label;
lbl_Tile.Visible = true;
//find picture box by tag or sth and then make this pB the parent
PictureBox pb_Tile = (PictureBox)gb_gridBox.Controls["Tile" + tb_Tag.X + tb_Tag.Y];
pb_Tile.BackgroundImage = pb_Tile.Image;
lbl_Tile.Parent = pb_Tile;
// pb_Tile.Visible = false;
if (pb_Tile.HasChildren)
{
lbl_Tile.Text = tb_Tile.Text; //parent has to be set to PictureBox
lbl_Tile.Visible = true;
lbl_Tile.ForeColor = Color.Black;
lbl_Tile.BackColor = Color.Transparent;
lbl_Tile.Location = pb_Tile.Location;
lbl_Tile.Refresh();
pb_Tile.Refresh();
gb_gridBox.Controls.Add(lbl_Tile);
lbl_Tile.BringToFront();
}
}
}
I want the Label.Text to be displayed on the PictureBox. This is why I set the PictureBox as the parent of the Label and the Label.BackColor as Transparent. But the Label just disappears behind the PictureBox...
Does anyone have a clue how to solve this or can give me a hint to another possibility of showing Text in front of the PictureBox?
Thanks in advance.
The problem I see is here:
lbl_Tile.Location = pb_Tile.Location;
The documentation for Location property:
Gets or sets the coordinates of the upper-left corner of the control relative to the upper-left corner of its container.
In your case the pb_Tile is the container of the lbl_Tile, so to achive the desired location you should use something like
lbl_Tile.Location = new Point(0, 0);
Also you should remove this line
gb_gridBox.Controls.Add(lbl_Tile);
because it changes the Parent of the label. parent.Controls.Add(child) and child.Parent = parent do one and the same.

How to position a borderless form under buttons

I have created 4 buttons dynamically and placed them horizontally using c# win forms.Now i want show a custom tooltip(actually its a borderless form) under each of the 4 buttons on mouse hover event.But how do i position my tooltip form under the buttons??
I have tried the code below but it does not work the desired way.
tooltip.Location = new System.Drawing.Point(b.Left, b.Top);
Where 'tooltip' is tooltip form object & 'b' is the dynamic button.Please advise with some code snippet.
private void B_MouseHover(object sender, EventArgs e)
{
var b = sender as Button;
//MessageBox.Show(Cursor.Position.ToString());
if(b!= null)
{
if (tooltip == null)
{
tooltip = new frmSecQStatToolTipDlg();
}
tooltip.Location = new System.Drawing.Point(b.Left, b.Bottom);
tooltip.data(b.Tag.ToString());
tooltip.Show();
}
}
The way you named it is a bit misleading. As I understand, what you call a tooltip is just a Form. You need to consider 2 things
(1) Form.StartPosition must be set to FormStartPosition.Manual
(2) Form.Location must be in screen coordinates. Note that the Button.Location you are trying to use is in button's parent client coordinates. Control.PointToScreen has to be used for conversion.
In your case, it should be something like this
tooltip.StartPosition = FormStartPosition.Manual;
var topLeft = b.PointToScreen(new Point(0, 0));
tooltip.Location = new Point(topLeft.X, topLeft.Y + b.Height);
When you show the tooltip you can control its location, check show method overloads: https://msdn.microsoft.com/en-us/library/system.windows.forms.tooltip.show.aspx

Why do the labels on my custom user control cause the mouseleave event to fire?

I have written a custom WPF UserControl. It's a square with a Grid named Base. To that grid I add an ellipse and two labels (volume and location), which are populated with text pulled from the properties of an object which is given as a parameter upon control instantiation.
Here's the XAML:
<UserControl x:Class="EasyHyb.SampleWellControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="100" d:DesignWidth="100">
<Grid x:Name="Base">
</Grid>
</UserControl>
And the constructor/event functions in the codebehind:
public SampleWellControl(int size, SourceSample sample)
{
InitializeComponent();
this.sample = sample;
this.Width = this.Height = size;
this.selected = SelectionStatus.Unselected;
double spacing = size / 4;
volume = new Label();
location = new Label();
volume.Content = String.Format("{0:0.00}", sample.volume);
location.Content = sample.well.well;
volume.HorizontalAlignment = location.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
volume.FontFamily = location.FontFamily = new System.Windows.Media.FontFamily("Meiryo UI");
volume.FontWeight = location.FontWeight = FontWeights.Bold;
volume.Background = location.Background = Base.Background = this.Background = Brushes.Transparent;
volume.Margin = new Thickness(0, spacing, 0, 0);
location.Margin = new Thickness(0, spacing * 2, 0, 0);
well = new Ellipse();
well.Width = well.Height = this.Width;
well.StrokeThickness = 3;
Base.Children.Add(well);
Base.Children.Add(volume);
Base.Children.Add(location);
this.MouseEnter += SampleWellControl_MouseEnter;
this.MouseLeave += SampleWellControl_MouseLeave;
this.MouseUp += SampleWellControl_MouseUp;
this.Cursor = Cursors.Hand;
UpdateFillAndStroke();
}
void SampleWellControl_MouseLeave(object sender, MouseEventArgs e)
{
RevertWell();
}
void SampleWellControl_MouseEnter(object sender, MouseEventArgs e)
{
HighlightWell();
}
public void HighlightWell()
{
if (this.selected == SelectionStatus.Pooled)
{
return;
}
if (this.selected == SelectionStatus.Unselected)
{
this.well.Stroke = this.strokes[SelectionStatus.Selected];
}
else
{
this.well.Stroke = this.strokes[SelectionStatus.Unselected];
}
}
public void RevertWell()
{
if (this.selected == SelectionStatus.Pooled)
{
return;
}
if (this.selected == SelectionStatus.Unselected)
{
this.well.Stroke = this.strokes[SelectionStatus.Unselected];
}
else
{
this.well.Stroke = this.strokes[SelectionStatus.Selected];
}
}
Basically, when the mouse enters the control, the stroke of the ellipse should change unless the well has undergone an operation to give it a "Pooled" status.
When the mouse enters the control, it responds exactly as I expect: the MouseEnter event handler fires. However, when a user moves the mouse over one of the labels inside the control, the MouseLeave event fires. So even though the label is ostensibly part of the control The pictures below show what I'm talking about. Print Screen removes the cursors, but I put blue dots to indicate where the cursor is:
Responding properly:
Now it seems to think the mouse has left the control:
I've tried adding MouseEnter and MouseLeave event handlers to the labels, but they don't fire. The cursor also changes from a hand to a pointer when the labels are moused over. I've tried adding MouseEnter and MouseLeave event handlers to the control after it's instantiated within another class. I added transparent backgrounds to the Grid, control, and labels, but that didn't make any difference either.
I also checked in my MouseLeave event handler to see if the mouse was over the control, and it seems that the control is not detecting the cursor as being over the control itself:
if(!this.IsMouseOver)
{
RevertWell();
}
//also tried IsMouseDirectlyOver
I would like MouseLeave to fire only when the cursor exits the square bounds of the control. How can I accomplish this while keeping the labels?
Use a combination of
IsHitTestVisible="False"
on all of your objects added to Base:
volume = new Label();
volume.IsHitTestVisible="False";
and then your container which has the events, give a background
<Grid x:Name="Base" Background="White">
(Also I wanted to comment but reputation is stupid)
Well shucks, after a lot of searching around it turns out the problem was indeed contained within another control. I had another UserControl class, EmptyWellControl, which had a Label. The text position within the label was calculated using the Label's Height property, which resulted in a nonsense value that made the label extend vertically well beyond the dimensions of the window. The label didn't have a background, but nevertheless interfered with the controls whose path it crossed. Since the empty and sample wells were all laid out on the same grid, every SampleWellControl was affected by these labels.

Wpf Thumb Drag not firing drag enter on other component

I have a wpf application with some Thumb controls which move items around a canvs. I want to detect when these thumbs are dragged over another element. However, the drag enter on the element which is dragged over is not fired. I know this code works as drag items that are not thumbs fire the event.
Is the drag event on the thumb not a drag event that other components listen to?
Any idea how to get this to work?
Apparently no. The only Thumb related Events are DragStarted, DragCompleted and DragDelta. The other events are for Drag and drop, like your DragEnter Event. These Events are especially for the Drag and drop, like dragging a file from the explorer into your application which has nothing to do with the Thumb. The names are similar but in fact very different.
One thing you could try is to use HitTesting while dragging, but remember that drag and drop and dragging a thumb takes the mouse capture, which disables input events on the other classes.
To achieve the simulation of a drag enter event when a thumb object is moved over another component I've had to do this:
Register event handler for the thumb drag delta
EventManager.RegisterClassHandler(typeof(Thumb), Thumb.DragDeltaEvent, new RoutedEventHandler(Thumb_DragDeltaEvent), true);
Then in the event handler see if the dragged element is over the element that is listening to the moving component
void Thumb_DragDeltaEvent(object sender, RoutedEventArgs e)
{
UIElement src = e.Source as UIElement ;
if (src != null)
{
Point srcPositionTopLeft = new Point(Canvas.GetLeft(src), Canvas.GetTop(src));
Point srcPositionBottomRight = new Point(srcPositionTopLeft.X + src.ActualWidth, srcPositionTopLeft.Y + ActualHeight);
Rect srcRect = new Rect(srcPositionTopLeft, srcPositionBottomRight);
Rect transformedSrcRect = src.TransformToAncestor(this.Parent).TransformBounds(srcRect);
Point trgPositionTopLeft = new Point(Canvas.GetLeft(this), Canvas.GetTop(this));
Point trgPositionBottomRight = new Point(trgPositionTopLeft.X + this.ActualWidth, trgPositionTopLeft.Y + this.ActualHeight);
Rect trgRect = new Rect(srcPositionTopLeft, srcPositionBottomRight);
Rect transformedTrgRect = this.TransformToAncestor(this.Parent).TransformBounds(trgRect);
if (transformedSrcRect.Contains(transformedTrgRect) ||
transformedSrcRect.IntersectsWith(transformedTrgRect))
{
//drag is over element
}
}
}
Remember to removed event handlers etc later.
Hope this helps someone in the future.

Scrollbar location is moving visible/nonvisible changing controls

I have a form with a scrollable panel and two controls sitting right on top of each other - one visible one not. Based on a certain condition when that form is activated I might swap the visible properties of the two controls. These controls are at the bottom of the scrollable panel. If when I leave that form I leave it scrolled to the bottom, go change the condition that will cause the controls' visibility to swap and go back to that form the visible control will have dropped about 200px down the page leaving a large gap. Anyone know what could be causing this? I tried resetting the scrollbar position to the top on form close but that just causes a smaller gap and sometimes the control to move higher into other controls. Any ideas?
Here is an example that reproduces the problem. If the mouse is moved over the red label, the visibility of button2 is changed to true which causes the scroll jumps back up to Button1.
public class Form123456 : Form {
public Form123456() {
Controls.Add(new UC1());
}
public class UC1 : UserControl {
Button b1 = new Button { Text = "Button1" };
Label lb = new Label { Text = "_", AutoSize = true, BackColor = Color.Red };
Button b2 = new Button { Text = "Button2", Visible = false };
Button b2b = new Button { Text = "x" };
Button b3 = new Button { Text = "Button3" };
public UC1() {
AutoScroll = true;
Dock = DockStyle.Fill;
b1.Location = new Point(0, 200);
b2.Location = new Point(0, 600);
lb.Location = new Point(70, 600);
b2b.Location = new Point(90, 600);
b3.Location = new Point(0, 800);
Controls.Add(b1);
Controls.Add(b2);
Controls.Add(lb);
Controls.Add(b2b);
Controls.Add(b3);
lb.MouseEnter += delegate {
b2.Visible = true;
};
lb.MouseLeave += delegate {
b2.Visible = false;
};
}
}
}
To fix it, one solution is to add this code:
protected override Point ScrollToControl(Control activeControl) {
return this.AutoScrollPosition;
}
Solution from:
Why does clicking in a text box cause an AutoScroll panel to scroll back to the top?
No repro. Sounds to me that you are doing more than just changing the Visible property. Whenever you assign the Location property, you have to add the AutoScrollPosition to compensate for the scroll state. Post code if this doesn't help.
Have you verified the order that you change visibility of the two controls?
The scroll bars on a container with auto scroll set to true will appear and disappear depending on the position of controls that are outside of the visible area of the control. Controls that are invisible do not count.
So in your case if you make both controls invisible at anytime, the scroll bars will disappear. They will come back when one control is made visible. So to make sure you don't have a jump in scroll bar position and controls position you should make sure that at no time are both controls invisible. Another solution is to have a pseudo-visible control on the container. That is a control that has its visibility set to true but it is not actually visible for the user (for example a dot of the color of the background, a label with no text ...). Position this control in the furthest position x,y and the scroll bars will never disappear..

Categories

Resources