Mouse move event on a TableLayoutPanel - winforms

I have an TableLayoutPanel object.
I want to be able to drag n drop a label in the table layout panel.
I have the following code:
private void tableLayoutPanel1_MouseMove(object sender, MouseEventArgs e) {
var formPos = this.PointToClient(tableLayoutPanel1.PointToScreen(e.Location));
if (!prevPoint.IsEmpty) {
int deltaX = formPos.X - prevPoint.X;
int deltaY = formPos.Y - prevPoint.Y;
lblClass.Location = new Point(lblClass.Location.X + deltaX, lblClass.Location.Y + deltaY);
prevPoint = formPos;
Invalidate();
}
}
The problem is that the MouseMove event fires only when I move the mouse from one cell to another, and doesn't fire when I move the mouse inside a cell.
Any solution for this?

Related

WPF Blur effect causing high CPU even when collapsed

We have to show a legal pop-up in our WPF app. When the pop-up is shown, we use blur effect on the view below.
Recently we recognized that this is causing high GPU usage. Because of the spinner control in the background. The more active content, the more GPU usage.
We collapse this spinner when the pop-up is shown based on a property. But this doesn't help. Only when we set it to collapsed in MainWindow.xaml it works.
We tried multiple things e.g. BitmapCache and other techniques but with no success so far.
Here an example:
https://github.com/rmoergeli/BlurEffectTest.git
I investigated that the problem in demo code hides in your animation: it doesn't stop on changing it visibility from visible to collapsed.
So I found a solution to stop animation on being collapsed with the help of MSDN resource.
public partial class Spinner : UserControl
{
private Canvas _content;
private Storyboard _rotationStoryboard;
public Spinner()
{
// Create a name scope for the page.
NameScope.SetNameScope(this, new NameScope());
DefineContent();
SizeChanged += Spinner_SizeChanged;
IsVisibleChanged += Spinner_IsVisibleChanged;
Loaded += Spinner_Loaded;
}
private void Spinner_Loaded(object sender, RoutedEventArgs e)
{
_rotationStoryboard.Begin(this, isControllable: true);
}
private void Spinner_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is bool isVisible && isVisible)
_rotationStoryboard.Resume(this);
else
_rotationStoryboard.Pause(this);
}
private void DefineContent()
{
_content = new Canvas();
//set content render transform origin point to center
_content.RenderTransformOrigin = new Point(0.5 , 0.5);
_content.RenderTransform = new RotateTransform(angle: 0);
// Assign the canvas a name by
// registering it with the page, so that
// it can be targeted by storyboard
// animations.
RegisterName("animatableCanvas", _content);
Content = _content;
DefineAnimatableContent();
// Create an animation and a storyboard to animate the
// canvas.
DoubleAnimation doubleAnimation = new DoubleAnimation
{
To = 360,
Duration = new Duration(TimeSpan.FromSeconds(3)),
RepeatBehavior = RepeatBehavior.Forever
};
Storyboard.SetTargetName(doubleAnimation, "animatableCanvas");
Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("RenderTransform.Angle"));
_rotationStoryboard = new Storyboard();
_rotationStoryboard.Children.Add(doubleAnimation);
}
private void DefineAnimatableContent() //renamed Refresh method
{
int n = Balls;
double size = BallSize;
_content.Children.Clear();
double x = ActualWidth / 2;
double y = ActualHeight / 2;
double r = Math.Min(x, y) - size / 2;
double doubleN = Convert.ToDouble(n);
for (int i = 1; i <= n; i++)
{
double doubleI = Convert.ToDouble(i);
double x1 = x + Math.Cos(doubleI / doubleN * 2d * Math.PI) * r - size / 2;
double y1 = y + Math.Sin(doubleI / doubleN * 2d * Math.PI) * r - size / 2;
var e = new Ellipse
{
Fill = BallBrush,
Opacity = doubleI / doubleN,
Height = size,
Width = size
};
Canvas.SetLeft(e, x1);
Canvas.SetTop(e, y1);
_content.Children.Add(e);
};
}
#region Event Handlers
private void Spinner_SizeChanged(object sender, SizeChangedEventArgs e)
{
//we dont need this anymore as we set content render transform origin point to content center
//Transform.CenterX = ActualWidth / 2;
//Transform.CenterY = ActualHeight / 2;
DefineAnimatableContent();
}
#endregion
//other logic
}
This code stops animation on changing Spiner control visibility. But sure you can pause and resume animation with any trigger you need.
N.B! Using this approach you define all the content (not only animarable parts) in code behind so you don't need Spinner.xaml resource anymore.

Show ToolTip until Mouse Leave

I need to show a tooltip while the mouse hovers on WinForms RadGridView header cells. The tooltip's text is different based on the current cell the mouse is hovering on. I don't want the tooltip to be disappeared until the mouse leaves the cell.
Maximum time is about 24 days... I suppose it's enough :)
Best way is to use ToolTipTextNeeded event:
private void radGridView1_ToolTipTextNeeded(object sender, ToolTipTextNeededEventArgs e)
{
// if cursor hover GridHeaderCellElement
var header = radGridView1.ElementTree.GetElementAtPoint(PointToClient(MousePosition)) as GridHeaderCellElement;
if (header != null)
{
e.ToolTip.AutoPopDelay = int.MaxValue; // 24.86 days
e.ToolTipText = "123";
}
}
or ( tnx to #checho )
private void radGridView1_ToolTipTextNeeded(object sender, ToolTipTextNeededEventArgs e)
{
// if cursor hover GridHeaderCellElement
if (sender is GridHeaderCellElement)
{
e.ToolTip.AutoPopDelay = int.MaxValue; // 24.86 days
e.ToolTipText = "123";
}
}

DataGridView Custom control enable button in Unedited mode

Does anyone know how to get the button visible all the time?.(Not only in edit mode of the cell)
I would like to take your attention to the answer of this question.
how to add ellipse button and textbox in current cell of datagridview in winforms
I could enhance this solution to see the button control in the cell for all the time. What I want is to get the popup box for the first click of the cell. This is the code to paint the button in uneditted mode.
// Finally paint the NumericUpDown control
Rectangle srcRect = new Rectangle(0, 0, valBounds.Width, valBounds.Height);
if (srcRect.Width > 0 && srcRect.Height > 0)
{
Bitmap renderingBitmap = new Bitmap(22, 18);
new TextButton().button.DrawToBitmap(renderingBitmap, srcRect);
graphics.DrawImage(renderingBitmap, new Rectangle(new Point(cellBounds.X+cellBounds.Width-24, valBounds.Location.Y-2), valBounds.Size),
srcRect, GraphicsUnit.Pixel);
}
A better option would be to embed a button on your DataGridView. This would give you more control over the use of DataGridView. See the following snippet:
Button b1 = new Button();
int cRow = 0, cCol = 0;
private void Form1_Load(object sender, EventArgs e)
{
b1.Text = "...";
b1.Visible = false;
this.dataGridView1.Controls.Add(b1);
b1.BringToFront();
this.dataGridView1.Paint += new PaintEventHandler(dataGridView1_Paint);
this.b1.Click += new EventHandler(b1_Click);
}
void b1_Click(object sender, EventArgs e)
{
//Implement your logic here
}
void dataGridView1_Paint(object sender, PaintEventArgs e)
{
if(cRow != 0 && cCol != 0)
{
Rectangle rect = new Rectangle();
rect = dataGridView1.GetCellDisplayRectangle(cRow ,cCol , false);
rect.X = rect.X + (2*dataGridView1.Columns[1].Width / 3);
rect.Width = dataGridView1.Columns[1].Width / 3;
b1.Bounds = rect;
b1.Visible = true;
}
}
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
cRow = e.RowIndex;
cCol = e.ColumnIndex;
}
In the above snippet the location of ellipses button is set to last clicked cell. The visibility is always true after a cell is clicked. In my opinion this would provide a far better control over the button's function,and is easier to maintain.

Can I make a WPF ListBox change selection on left button press only

I have a WPF ListBox operating in single selection mode. I am adding drag and drop to move items around. Currently the ListBox selection responds to both left button pressed and then with mouse moves with left button down. So after I wait for the MinimumVerticalDragDistance to start a drag operation, a different item could be selected. Dragging either the unselected orginal item or dragging the new selected item is confusing. Adding 'e.Handled=true' in xxx_MouseMove or xxx_PreviewMouseMove does not do anything. Any ideas on suppressing this selection due to mouse moves with left button down?
The best kludge I came up with is to cancel the ListBox's "Selection by dragging" in the IsMouseCapturedChanged event.
public partial class MainWindow : Window
{
Rect? dragSourceGestureRect;
bool busy;
public MainWindow()
{
InitializeComponent();
listBox.ItemsSource = Enumerable.Range(1, 9);
listBox.PreviewMouseLeftButtonDown += listBox_PreviewMouseLeftButtonDown;
listBox.IsMouseCapturedChanged += listBox_IsMouseCapturedChanged;
listBox.MouseMove += listBox_MouseMove;
}
void listBox_IsMouseCapturedChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (busy)
return;
if (!listBox.IsMouseCaptured)
dragSourceGestureRect = null;
else if (dragSourceGestureRect.HasValue)
{
busy = true;
{
//tell the ListBox to cancel it's "Selection by dragging"
listBox.ReleaseMouseCapture();
//Now recapture the mouse for canceling my dragging
listBox.CaptureMouse();
}
busy = false;
}
}
void listBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var center = e.GetPosition(listBox);
dragSourceGestureRect = new Rect(
center.X - SystemParameters.MinimumHorizontalDragDistance / 2,
center.Y - SystemParameters.MinimumVerticalDragDistance / 2,
SystemParameters.MinimumHorizontalDragDistance,
SystemParameters.MinimumVerticalDragDistance);
}
void listBox_MouseMove(object sender, MouseEventArgs e)
{
if (!dragSourceGestureRect.HasValue || dragSourceGestureRect.Value.Contains(e.GetPosition(listBox)))
return;
dragSourceGestureRect = null;
var data = new DataObject(DataFormats.UnicodeText, "The Data");
DragDrop.DoDragDrop(listBox, data, DragDropEffects.Copy);
e.Handled = true;
}
}

How to use the slider in WPF to Zoom in and out of an image?

I am trying to use slider to control the Zoom in and Zoom out of any image.
I have written a code:
private void image1_MouseMove(object sender, MouseEventArgs e)
{
if (!image1.IsMouseCaptured) return;
var tt = (TranslateTransform)((TransformGroup)
image1.RenderTransform).Children.First(tr => tr is TranslateTransform);
Vector v = start - e.GetPosition(border1);
tt.X = origin.X - v.X;
tt.Y = origin.Y - v.Y;
}
Here it is working fine. using mouse scroll. But I want to use the slider for the same functioning.
But unable to put the same behaviour like mouse scroll using slider.
I am very new to WPF and its control, so any help with details is highly appreciated.
How can i implement the same finctionality of Zoom in - out using the slider?
After a lot of research and coding I found that its a very simple application and very simple coding too, to Zoomin and Zoomout the image using a slider. what you need is to put a slider in the area of your choice. and put the following code.
private void slider1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
TransformGroup transformGroup = (TransformGroup)image1.RenderTransform;
ScaleTransform transform = (ScaleTransform)transformGroup.Children[0];
double zoom = e.NewValue;
transform.ScaleX = zoom;
transform.ScaleY = zoom;
}
Now I already have the code so that the image will Zoomin and Zoomin using the mousewheel.
private void image1_MouseWheel(object sender, MouseWheelEventArgs e)
{
TransformGroup transformGroup = (TransformGroup)image1.RenderTransform;
ScaleTransform transform = (ScaleTransform)transformGroup.Children[0];
double zoom = e.Delta > 0 ? .2 : -.2;
transform.ScaleX += zoom;
transform.ScaleY += zoom;
slider1.Value += zoom;
}
Now when you put
slider1.value += zoom;
Then changes in the mousewheel and in the changes in the slider change the zoom of the picture.
Remember the difference of implementation between mouse wheel and slider. In mouse wheel MouseWheelEventsArgs "e" and e.Delte value is positive and negative depends on the mousewheel up or mousewheel down. But in Slider RoutedPropertyChangesEventsArgs value is positive or negative according to the sldier up and down. You don't need to specify here. Just
zoom = e.NewValue;
I hope it will help.
You have to code a ScaleTransform in your code. This is a part of my code that do this, I don't put everything but it's a base for you.
For the slider, you have to bind the Zoom property to the Value of the Slider.
private double m_dCurZoom = 1.0;
private ScaleTransform m_transZoom;
public ScaleTransform TransZoom
{
get { return m_transZoom; }
}
private TranslateTransform m_transPan;
public double Zoom
{
get { return m_dCurZoom; }
set
{
double oldzoom = m_dCurZoom;
if (m_dCurZoom != value)
{
m_dCurZoom = value;
OnPropertyChanged("Zoom");
UpdateZoom(oldzoom);
}
}
}
public void UpdateZoom(double oldzoom)
{
// Are we visible?
if (m_root == null)
return;
// Get parent
FrameworkElement parent = GetRootParent();
if (parent == null)
return;
// Center point of the window
Point ptCenter = new Point(parent.RenderSize.Width / 2, parent.RenderSize.Height / 2);
// Translate into canvas coordinates
ptCenter = m_root.TranslatePoint(ptCenter, m_canvas);
// Update the zoom
m_transZoom.ScaleX = m_dCurZoom;
m_transZoom.ScaleY = m_dCurZoom;
m_transPan.X -= ptCenter.X * m_dCurZoom - ptCenter.X * oldzoom;
m_transPan.Y -= ptCenter.Y * m_dCurZoom - ptCenter.Y * oldzoom;
ResizeElementContents();
OnPropertyChanged("Zoom");
}

Resources