kirsan31 / winforms-datavisualization

System.Windows.Forms.DataVisualization provides charting for WinForms applications.
MIT License
47 stars 19 forks source link

Single left mouse click selects the chart and somehow anchors the scroll of a panel to chart's location #51

Closed idenchev closed 10 months ago

idenchev commented 10 months ago

I have came across to this problem recently. It seems that a single left mouse click on a chart somehow selects it. This by itself is not a problem, because highlighting of the chart is barely visible, but it has further implications, which are described later. Below can be seen a depiction of the problem in an example of two charts next to each other. If you click on the left chart it is highlighted: 1 Then when you click on the right chart the focus is moved on it: 2 Highlighting above looks like a dotted rectangular which is placed over the chart borderline. I need to mention that this highlighting is not always displayed, but still focus remains on the clicked chart.

In my application I have a panel with multiple charts. Auto-scrolling is enabled. There are no defined events when user left-clicks on a chart. Right clicks open a ContextMenuStrip with different options. The problem is following. If the user accidently left clicks on a chart from the second row of charts in the panel and then scrolls with the mouse to for example the pre-last row of charts and right-clicks on a chart and from the pop-up menu calls a function (for example Zoom chart in new window), which results in opening a new window (like additional Winform or even a MsgBox), then when user closes the additional form or just return to the main form with charts, the scroll of the panel is immediately and automatically positioned back to the location of the chart that was left-clicked. This is especially unpleasant when you have a panel with let's say 60 charts and you are moved back to a location far away from the chart which you are working with. Below can be found a depiction of the explained problem.

  1. Users left-clicks on the right chart from the second row of charts (chart is marked with blue arrow and scroll location with red arrow): 3

  2. User scrolls to the pre-last row of charts and right-clicks on the right chart to call a pop-up menu from where user selects some option, which opens a new window or calls a message box. 4

  3. After returning to the form with charts the panel is automatically positioned on the chart that was left-clicked in Step 1 (although the chart now is not with highlighted borderline). 5

This issue happens in .Net 7. Before my application was running on .Net Framework 4.7 with the in-built charting object and explained problem was not happening. I am not sure what is causing this strange behaviour and am wondering if there could be some work-around. Thank you!

kirsan31 commented 10 months ago

It seems to me that what you are describing here is in no way connected with the chart control. You can replace it with any other control and get the same behavior. As I see it, an elementary workaround is to select a chart before opening the menu.

idenchev commented 10 months ago

I was not able to reproduce the control selection with other controls like DGV or Label. It appears that this behaviour is something new in .Net 7 and doesn't exist in .Net Framework 4.7, so I guess it is framework-related. You are completely right that the workaround is to select the right-clicked chart control when I trigger an option from the pop-up menu - so far I was not doing that. I did it like this:

parentObject.Select()

I will post below the code just in case that someone else gets into the same problem.

        Dim myItem As ToolStripMenuItem = CType(sender, ToolStripMenuItem)
        Dim cms As ContextMenuStrip = CType(myItem.Owner, ContextMenuStrip)

        Dim parentObject As New System.Windows.Forms.DataVisualization.Charting.Chart
        Try
            parentObject = CType(Me.Controls.Find(cms.SourceControl.Name, True)(0), System.Windows.Forms.DataVisualization.Charting.Chart)
        Catch ex As Exception

        End Try

        parentObject.Select()

I hope this selection of the right-clicked chart control will not lead to other unexpected complications. Easier will be somehow to cancel the left click selection, but have no idea how I can do this, so I will proceed with you suggestion. Thank you so much! :)

kirsan31 commented 10 months ago

I was not able to reproduce the control selection with other controls like DGV or Label.

Did you tried something like multirow TextBox or RichTextBox? If this behavior exists only with chart control and you can provide some small repro project, I will look into it...

idenchev commented 10 months ago

Yes, I will do additional tests. I can also try to create a repository, but it will take some time, because I have no experience with that and also I am using VB, so will need to create a C# project.

kirsan31 commented 10 months ago

I can also try to create a repository, but it will take some time, because I have no experience with that

No need do create a repository. You need to create simple c# project that reproduce issue, zip it and attach to message here.

idenchev commented 10 months ago

As you suggested I created a simple c# project and it is attached here. The behaviour in question can be easily tested. For example you can left click on any of the upper charts - the chart will be highlighted. Then you scroll down towards the end of the panel and right click on any chart and select Show message from the popup menu. After you press OK in the message box you will be scrolled-back to the chart that you initially left clicked. I placed some additional controls. The thing is that there is similar behaviour. If you click on the second DGV and scroll down to any chart and right click it, then after closing the message you will be positioned exactly on the second DGV. This applies to the textboxes as well, but not to the labels. The third experiment is if you click on a chart, so that to highlight it, then you click on a DGV and then the chart is no longer selected (neither is the DGV). Then repeat the steps with scrolling down and right clicking and finally you will be positioned on the DGV. Apparently the DGV was also selected after clicking, although not highlighted. From what I experimented this behaviour is related to .Net 7, but it does not exist in .Net Framework 4.7. TestChartSelection.zip

kirsan31 commented 10 months ago

The thing is that there is similar behaviour. If you click on the second DGV and scroll down to any chart and right click it, then after closing the message you will be positioned exactly on the second DGV. This applies to the textboxes as well, but not to the labels.

From your experiments it is clear that this behavior is typical for selectable controls in net7 (and chart is one of them). So this is not chart only problem. You can try to rise an issue/question in WinForms repo why this behavior was changed from .Net Framework 4.7 (to avoid unnecessary questions - in your example remove the chart controls and put textboxes instead)...

idenchev commented 10 months ago

Just to mention that I found another workaround, which is applicable only when charts are added during runtime. The idea is to create a new class, which inherits your class and to set the property ControlStyles.Selectable of SetStyle method to False. Like that the charts are no longer selectable and the explained problem in my question is no longer happening. This change is not affecting in any negative way the interaction with charts - user still can zoom them, call different functions after right-click pop-up menu, also can modify the charts and so on. The code that I used is below. This solution is not applicable when charts are added with Designer. In this case a partial workaround is the described one earlier in this thread with the addition of parentObject.Select(). This solves the issue when user clicks on a chart (and thus selects it), then scrolls to somewhere else in the panel and right-clicks on another chart and calls another form to appear or messagebox to be displayed and after returning to the form with the charts, he is returned back to the initially clicked chart. With parentObject.Select() this happens no longer. But another issue can happen in following scenario: user right clicks on a chart for example at the bottom of the panel and do some interactions with that chart. Then he scrolls back to the top of the panel to check another chart, but this time without clicking on it. Then user switchs to another WinForm in the application and then returns to the form with the charts. In this case the panel scrolls automatically to the bottom of the panel, where is the location of the chart, which was clicked.

Code for new class creation:

Public Class ChartNoSel
    Inherits System.Windows.Forms.DataVisualization.Charting.Chart

    Public Sub New()
        MyBase.SetStyle(ControlStyles.Selectable, False)
    End Sub

End Class

Then instead of declaring the chart like:

Dim Chart = New System.Windows.Forms.DataVisualization.Charting.Chart()

It is declared with the new class:

Dim Chart = New ChartNoSel()
kirsan31 commented 10 months ago

This solution is not applicable when charts are added with Designer.

You still can use your subclass with designer. MyChart here is subclass of Chart: image

idenchev commented 10 months ago

Fantastic! Have I ever said that you are a magician? 🥇