Scrolling cause flickering when controlling MouseWheel events - c#

I'm trying to understand what is executing before the MouseWheel event.
What I've done:
I have a form which has AutoScroll property set to true. There is a control (ZEDGRAPH) at the top and the bottom of this form.
To overcome the issue of scrolling and zooming at the same time I captured the mousewheel += new MouseEvenHandler(mymethod) for the form.Then using a bool variable I keep track of when the control (ZEDGRAPH) has focus and when it does not.
When it has focus I make verticalscroll.value = (int)mydesiredposition;
This works in accomplishing what I wanted which is to ignore the mousewheel event in the form and focus on the control.
What I am struggling with is the fact that when I scroll the form flickers every time and scrolls down before coming to the set scrollbar value.
So what I am wondering is what is getting triggered before this mouseeventhandler that causes it to flicker and is there a relatively simple workaround this?
My code snapshot:
public Form(Form1 f)
{
InitializeComponent();
this.MouseWheel += new MouseEventHandler(mousewheel);
}//end of constructor
//
//
bool mousehoverZedGraph1 = false;
bool mousehoverZedGraph2 = false;
//
//
private void zedGraphControl1_MouseHover(object sender, EventArgs e)
{
mousehoverZedGraph1 = true;
return;
}
private void mousewheel(object sender, MouseEventArgs e)
{
if (mousehoverZedGraph1 == true)
{
VerticalScroll.Enabled = false;
VerticalScroll.Value = 0;
return;
}
else if (mousehoverZedGraph2 == true)
{
VerticalScroll.Value = 429;
VerticalScroll.Enabled = false;
}
else
{
//VerticalScroll.Value += e.Delta;
}
}
private void Form_MouseEnter(object sender, EventArgs e)
{
mousehoverZedGraph1 = mousehoverZedGraph2 = false;
VerticalScroll.Enabled = true;
}
A small video highlighting the flicker:

Related

Zooming in ComboBox not working as expected

I have an application that scans an image to display on the application. After the image is scanned, I have the option to zoom the image. There's a combo box on the application that display the zoom percentage as well.
I can zoom fine using my mouse wheel and the combo box % changes accordingly which is fine. The problem happens if I manually select the combo box and select a zoom percentage, say 50%, then there's no changes at all.
Code:
private void ImageBox_ZoomLevelsChanged(object sender, EventArgs e)
{
this.FillZoomLevels();
}
private void ZoomComboBox_Click(object sender, EventArgs e)
{
}
private void FillZoomLevels()
{
ZoomComboBox.Items.Clear();
foreach (int zoom in ImageBox.ZoomLevels)
ZoomComboBox.Items.Add(string.Format("{0}%", zoom));
}
Am I doing anything wrong? Appreciate any help.
When there is more than one control on the Panel, and the ScrollBars are shown, the MouseWheel event of the Panel would be raised, but if there's only a PictureBox on the Panel whose Image large enough to make the panel's ScrollBars visible, then the MouseWheel event of the Panel won't be raised, instead, the Form's MouseWheel event fires.
In the following sample, I just add a PictureBox onto the Panel without any other controls added, set a large Image to the PictureBox which make the Panel's ScrollBars invisible, since there's only one control on the panel, the MouseWheel event of the Panel won't be raised, but the Form's MouseWheel event be raised, we handle this event instead, handle the Form's KeyDown and KeyUp events as well.
Furthermore, set the SizeMode of the PictureBox to StretchImage instead of AutoSize, thus when we change the size of the PictureBox, the Image in the PictureBox will resize to fit the PictureBox.
The PictureBox.Scale() method won't help you in this screnario, change the size of the PictureBox instead.
public partial class Form4 : Form
{
public Form4()
{
InitializeComponent();
}
bool ctrlKeyDown;
bool shiftKeyDown;
private void Form4_Load(object sender, EventArgs e)
{
this.ctrlKeyDown = false;
this.shiftKeyDown = false;
//If there's only PictureBox control on the panel, the MouseWheel event of the form raised
//instead of the MouseWheel event of the Panel.
this.MouseWheel += new MouseEventHandler(Form4_MouseWheel);
this.KeyDown += new KeyEventHandler(Form4_KeyDown);
this.KeyUp += new KeyEventHandler(Form4_KeyUp);
//this is important for zooming the image
this.pictureBox2.SizeMode = PictureBoxSizeMode.StretchImage;
}
void Form4_KeyUp(object sender, KeyEventArgs e)
{
this.ctrlKeyDown = e.Control;
this.shiftKeyDown = e.Shift;
}
void Form4_KeyDown(object sender, KeyEventArgs e)
{
this.ctrlKeyDown = e.Control;
this.shiftKeyDown = e.Shift;
}
void Form4_MouseWheel(object sender, MouseEventArgs e)
{
bool IsGoUp = e.Delta > 0 ? true : false;
if (this.ctrlKeyDown)
{
if (IsGoUp && this.panel1.HorizontalScroll.Value > 5)
{
this.panel1.HorizontalScroll.Value -= 5;
}
if (!IsGoUp && this.panel1.HorizontalScroll.Value < this.panel1.HorizontalScroll.Maximum - 5)
{
this.panel1.HorizontalScroll.Value += 5;
}
}
else if (this.shiftKeyDown)
{
int hStep = (int)(this.pictureBox2.Image.Width * 0.02);
int vStep = (int)(this.pictureBox2.Image.Height * 0.02);
if (IsGoUp)
{
this.pictureBox2.Width += hStep;
this.pictureBox2.Height += vStep;
}
else
{
this.pictureBox2.Width -= hStep;
this.pictureBox2.Height -= vStep;
}
}
else
{
if (IsGoUp && this.panel1.VerticalScroll.Value > 5)
{
this.panel1.VerticalScroll.Value -= 5;
}
if (!IsGoUp && this.panel1.VerticalScroll.Value < this.panel1.VerticalScroll.Maximum - 5)
{
this.panel1.VerticalScroll.Value += 5;
}
}
}
}

WPF DragMove() causes issues

I'm trying to figure out if there's an elegant solution to the problem I've been faced with.
So basically, I designed a borderless loading splash screen which is completely movable via dragging. I find that this happens if the splash screen gets hidden via Hide(), then displays a window via ShowDialog() with the owner set to the splash screen. Things get extremely buggy, but only if you're in mid-drag (with left mouse button down). You become unable to click or move anything, even Visual Studio becomes unresponsive unless you explicitly alt-tab out of the application.
Considering I know when I'm going to spawn the window, I was thinking maybe there'd be a way to cancel the DragMove operation, but I'm having no luck. What I've figured out is that DragMove is synchronous, so I'd guess it'd have to be cancelled from a different thread or in an event callback.
Edit:
public partial class Window_Movable : Window
{
public Window_Movable()
{
InitializeComponent();
}
public Boolean CanMove { get; set; } = true;
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (CanMove == false)
return;
Task.Factory.StartNew(() => {
System.Threading.Thread.Sleep(1000);
Dispatcher.Invoke(() => {
Hide();
new Window_Movable() {
Title = "MOVABLE 2",
CanMove = false,
Owner = this
}.ShowDialog();
});
});
DragMove();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Console.WriteLine("DING");
}
}
I had the same problem and found out that DragMove() method is a problem.
https://groups.google.com/forum/#!topic/wpf-disciples/7OcuXrf2whc
To solve I decided to refuse from using it and implement moving logic.
I've combined some solutions from
https://www.codeproject.com/Questions/284995/DragMove-problem-help-pls
and
C# WPF Move the window
private bool _inDrag;
private Point _anchorPoint;
private bool _iscaptured;
private void AppWindowWindowOnMouseMove(object sender, MouseEventArgs e)
{
if (!_inDrag)
return;
if (!_iscaptured)
{
CaptureMouse();
_iscaptured = true;
}
var mousePosition = e.GetPosition(this);
var mousePositionAbs = new Point
{
X = Convert.ToInt16(_appWindowWindow.Left) + mousePosition.X,
Y = Convert.ToInt16(_appWindowWindow.Top) + mousePosition.Y
};
_appWindowWindow.Left = _appWindowWindow.Left + (mousePositionAbs.X - _anchorPoint.X);
_appWindowWindow.Top = _appWindowWindow.Top + (mousePositionAbs.Y - _anchorPoint.Y);
_anchorPoint = mousePositionAbs;
}
private void AppWindowWindowOnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (_inDrag)
{
_inDrag = false;
_iscaptured = false;
ReleaseMouseCapture();
}
}
private void AppWindowWindowOnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_anchorPoint = e.GetPosition(this);
_anchorPoint.Y = Convert.ToInt16(_appWindowWindow.Top) + _anchorPoint.Y;
_anchorPoint.X = Convert.ToInt16(_appWindowWindow.Left) + _anchorPoint.X;
_inDrag = true;
}
I've spend all yesterday evening and find a more hacky but more functional solution. Which support Maximized state and not require manual coordinate calculation.
private bool _mRestoreForDragMove;
private void OnAppWindowWindowOnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ClickCount == 2)
{
if (_appWindowWindow.ResizeMode != ResizeMode.CanResize &&
_appWindowWindow.ResizeMode != ResizeMode.CanResizeWithGrip)
{
return;
}
_appWindowWindow.WindowState = _appWindowWindow.WindowState == WindowState.Maximized
? WindowState.Normal
: WindowState.Maximized;
}
else
{
_mRestoreForDragMove = _appWindowWindow.WindowState == WindowState.Maximized;
SafeDragMoveCall(e);
}
}
private void SafeDragMoveCall(MouseEventArgs e)
{
Task.Delay(100).ContinueWith(_ =>
{
Dispatcher.BeginInvoke((Action)
delegate
{
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
_appWindowWindow.DragMove();
RaiseEvent(new MouseButtonEventArgs(e.MouseDevice, e.Timestamp, MouseButton.Left)
{
RoutedEvent = MouseLeftButtonUpEvent
});
}
});
});
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
if (_mRestoreForDragMove)
{
_mRestoreForDragMove = false;
var point = PointToScreen(e.MouseDevice.GetPosition(this));
_appWindowWindow.Left = point.X - (_appWindowWindow.RestoreBounds.Width * 0.5);
_appWindowWindow.Top = point.Y;
_appWindowWindow.WindowState = WindowState.Normal;
_appWindowWindow.DragMove();
SafeDragMoveCall(e);
}
}
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
_mRestoreForDragMove = false;
}
The thing is to send LeftMouseButtonUp event after a short delay to avoid blocking from DragMove()
Sources for last solve:
DragMove() and Maximize
C# WPF - DragMove and click
And one more completely different solution. To make a window movable you can use CaptionHeight of WindowChrome.
i.e.
var windowChrome =
WindowChrome.GetWindowChrome(appWindow.Window);
windowChrome.CaptionHeight = MainWindowToolbar.Height;
WindowChrome.SetWindowChrome(appWindow.Window, windowChrome);
but you should also set attached property WindowChrome.IsHitTestVisibleInChrome="True" for all controls in the window.

Make a PictureBox visible / not visible using MouseHover

I think this is a stupid question, but I don't understand what is happening here.
I use this code:
private void pictureBox1_MouseHover(object sender, EventArgs e)
{
pictureBox1.Visible = false;
pictureBox1.BackColor = Color.Black;
}
private void pictureBox1_MouseLeave(object sender, EventArgs e)
{
pictureBox1.Visible = true;
}
The problem is: The picturebox changes color to black if mouse is over picturebox, but the visibility doesn't change. Why?
I think your problem is as soon as you hover the picture it really disappears (that's why you see the back color turn to black, the event is firing). However the picture disappears which lead to situation where your mouse is not on the picture anymore, therefore Mouse_Leave event firing.
You can use MouseEnter event instead of MouseHover and bool field isHover that you can use in attempt to reduce flickering :
public partial class Form1: Form
{
bool isHover = false;
private void pictureBox1_MouseEnter(object sender, EventArgs e)
{
if(isHover) return;
// with MouseHover this control visibility appears to be locked with MouseEnter it is not
pictureBox2.Visible = false;
pictureBox2.BackColor = Color.Black;
}
private void pictureBox1_MouseLeave(object sender, EventArgs e)
{
if(!isHover) return;
isHover = false;
pictureBox2.Visible = true;
}
...
}

ToolStripDropDown loses mouse autoclose

Not sure how to explain this, but:
there is a control MyPopup, made out of ToolStripDropDown;
there are many based on MyPopup controls (call them popups);
there are no problems to open popup from the Form;
but there is is a problem to open popup from popup.
Problem is what after child popup is closed, parent popup stays on screen even when its parent Form get focus. The only way to close that stuck parent popup is to get focus to it (with the mouse) and hit Esc.
To have popup able to show another popup I have to trick Closing event:
void Popup_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{
// prevent from closing when stay
if (_stay && e.CloseReason != ToolStripDropDownCloseReason.CloseCalled )
{
e.Cancel = true;
return;
}
}
Before of after closing child popup, parent popup has:
value of _stay is False;
the value of Popup.AutoClose is True;
I tried to "bring" mouse focus back to the parent popup with the following:
TopLevel=true no luck;
Focus(); no luck;
Focused=true; no luck;
AutoClose=true; no luck;
Captured=true; no luck;
Also tried setting above value to False and then to True, still no luck.
And here is some more code, which could be useful or not:
public class MyPopup : UserControl
{
protected bool _stay = false;
private ToolStripDropDown _popup;
private ToolStripControlHost _host;
public MyPopup()
{
// create popup
_popup = new ToolStripDropDown();
_popup.Margin = _popup.Padding = Padding.Empty;
_popup.AutoSize = false;
_popup.Closing += Popup_Closing;
// add host
_host = new ToolStripControlHost(this);
_host.Margin = _host.Padding = Padding.Empty;
_host.AutoSize = false;
_popup.Items.Add(_host);
}
public void Show(Control parent, int x, int y)
{
_popup.Show(parent, x, y);
}
public new void Hide()
{
_popup.Close();
}
private void Popup_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{
// prevent from closing when stay
if (_stay && e.CloseReason != ToolStripDropDownCloseReason.CloseCalled )
{
e.Cancel = true;
return;
}
}
protected void PopupChildClosedDefaultEvent(object sender, EventArgs e)
{
// hide popup if mouse is outside of client region when closing child popup
if (!ClientRectangle.Contains(PointToClient(MousePosition)))
Hide();
else
{
// >> here I am trying different things <<
_popup.AutoClose = false;
_popup.AutoClose = true;
}
}
}
public class PopupParent: MyPopup
{
private void TestChildren()
{
_stay = true;
PopupChild popup = new PopupChild();
popup.Show(button1, 0, 0);
popup.Closed += PopupChildClosedDefaultEvent;
_stay = false;
}
}
public class PopupChild: MyPopup
{
}
Question: Is there any way to fix "broken" popup after it has lost its ability to autoclose on mouse event (clicking somewhere outside of the client area)?
Ok, morning bring some freshness to brains and I managed to solve that issue with following:
_popup.Close();
_popup.Show(_parent, _x, _y);
So I have to reshow popup to have it functioning as before. It flickers, but works.

Enabling/Disabling Moveup/MoveDown buttons on a ListView

with a form like this:
I wrote this piece of code to take care of enable/disable logic for moveup/down buttons when they click on at item ( we don't care about Avaiable list on the left, we just care about Selected list on the right)
private void SelectedLV_SelectedIndexChanged(object sender, EventArgs e)
{
// what to do wth move up button
if (SelectedLV.SelectedIndices.Count == 1 && SelectedLV.SelectedItems[0].Index > 0)
{
MoveUpBtn.Enabled = true;
}
else
{
MoveUpBtn.Enabled = false;
}
//what to do with move down button
if (SelectedLV.SelectedIndices.Count == 1 && SelectedLV.SelectedItems[0].Index < SelectedLV.Items.Count - 1)
{
MoveDownBtn.Enabled = true;
}
else
{
MoveDownBtn.Enabled = false;
}
}
I think it works fine for that scenario but my question is what about when we click off of Selected Listview, What is good logic to handle that and Disable Both Moveup/Down buttons?
I don't want them be enabled when we are not inside SelectedListView...
Also if you notice any issue with the code I pasted please let me know.
Thanks
You are about to shoot your foot with the focus requirement. These kind of UI updates are best done with the Application.Idle event, it only runs when nothing important is happening. And can help to eliminate a lot of event handlers. Like this:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
Application.Idle += Application_Idle;
this.FormClosed += delegate { Application.Idle -= Application_Idle; };
}
void Application_Idle(object sender, EventArgs e) {
bool focusOk = this.ActiveControl == SelectedLV;
bool selectOk = SelectedLV.SelectedIndices.Count == 1;
int index = selectOk ? SelectedLV.SelectedIndices[0] : -1;
MoveUpBtn.Enabled = focusOk && selectOk && index > 0;
MoveDownBtn.Enabled = focusOk && selectOk && index < SelectedLV.Items.Count-1;
}
}
Don't forget to set the focus back in the buttons' Click event handler. And don't forget about the ListView.HideSelection property. Set it to False so that focus doesn't matter anymore.
The problem is once you click on the Move buttons, then you are outside of the SelectedListView control, so the logic should really be based on if you have a correct index value or not:
private void SelectedLV_SelectedIndexChanged(object sender, EventArgs e)
if (SelectedLV.SelectedIndicies.Count == 0) {
MoveUpBtn.Enabled = false;
MoveDownBtn.Enabled = false;
} else {
// normal processing
}

Categories

Resources