问题
When I drag a toolstrip to the left (perhaps just to get it in the corner) with another toolstrip in that same toolstrip panel, the one I'm dragging jumps down to a 'new' row, as if I had moved it down. It's quite tricky to explain, so here's a couple of diagrams.
Diagram A: I move the toolstrip to the left, and 'accidentally' go too far left (well only by a couple of dozen pixels, which users can easily do).
Diagram B: This happens, the dragged toolstrip drops down a row.
How can I prevent this new row from being 'created'? As a last resort, I would be happy to prevent new rows being created under any circumstances (e.g: If the user intended to drag it down to create a new row).
I've experimented with LayoutStyle to no avail.
回答1:
There's probably a couple ways to do this. I've experimented with a few, but none are perfect. I would say the least complicated way I found is to set the maximum size of the ToolStripPanel like Hans mentioned, and also to subclass the ToolStrip and override OnLocationChanged
(or assign an event handler to LocationChanged
rather than subclassing, but you'd have to assign a handler to each ToolStrip).
public class ToolStripEx : ToolStrip
{
protected override void OnLocationChanged(EventArgs e)
{
if (this.Location.Y >= this.Parent.MaximumSize.Height)
{
this.Location = new Point(this.Location.X, 0);
}
else
{
base.OnLocationChanged(e);
}
}
}
Note: This causes the mouse to jump back and forth when trying to drag the ToolStrip down, due to the fact that the Location is reset after it already changed, so it is essentially moving down, then immediately jumping back up.
It's also worth mentioning that this may be an annoyance to the user, especially if they are purposely trying to put the ToolStrip in a new row, so I wouldn't really recommend doing this. But since you asked, there it is.
Update with complete steps and code:
I created a new blank Windows Forms project. I added a new file ToolStripEx.cs
to the solution, and this is what is inside:
Updated for the other panels and their Orientation
using System;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
public class ToolStripEx : ToolStrip
{
protected override void OnLocationChanged(EventArgs e)
{
if (this.Parent is ToolStripPanel)
{
ToolStripPanel parent = this.Parent as ToolStripPanel;
if (parent.Orientation == Orientation.Horizontal)
{
if (this.Location.Y != 0)
{
this.Location = new Point(this.Location.X, 0);
return;
}
}
else if (parent.Orientation == Orientation.Vertical)
{
if (this.Location.X != 0)
{
this.Location = new Point(0, this.Location.Y);
return;
}
}
}
base.OnLocationChanged(e);
}
}
}
Then I built the solution so the ToolStripEx
class will show up in the Toolbox.
Then I put a regular ToolStripContainer
onto the form from the Toolbox, set Dock
to Fill
, set the colors, etc.
Then I dragged two ToolStripEx
s (with the cog icon you mentioned) from the Toolbox to the TopToolStripPanel
. I set their colors and renderers and whatnot.
This is what Form1.cs
looks like:
Updated to set the other maximum sizes
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.toolStripContainer1.TopToolStripPanel.MaximumSize = new Size(0, toolStripEx1.Height);
this.toolStripContainer1.LeftToolStripPanel.MaximumSize = new Size(toolStripEx1.Height, 0);
this.toolStripContainer1.BottomToolStripPanel.MaximumSize = new Size(0, toolStripEx1.Height);
this.toolStripContainer1.RightToolStripPanel.MaximumSize = new Size(toolStripEx1.Height, 0);
}
}
}
Note: This code prevents any of the panels from expanding their rows (or columns if they have an Orientation
of Orientation.Vertical
) If you want the side panels to be able to expand, don't set their maximum size and get rid of the else if parent.Orientation == Orientation.Vertical
section.
That should be all there is to it. I ran this, and both of the ToolStripEx
s did not disappear when moving them around.
Like Hans said, the ToolStrip
class is pretty quirky and pretty much any solution to your problem is not going to be perfect unless you develop your own controls from the ground up with your needs in mind.
If for some reason you need to extend the ToolStripContainer
class, keep it separate from the new ToolStripEx
class. I suspect that having the nested classes was causing you to still be using the regular ToolStrip
rather than the ToolStripEx
class.
Another Update - fixing the mouse jumping:
I found this by accident when experimenting to get rid of the mouse cursor problem. Add this to the ToolStripEx
class:
protected override void OnBeginDrag(EventArgs e)
{
//base.OnBeginDrag(e);
}
Strangely enough, that seems to cut down significantly on the toolstrip's resistance to being dragged outside of a panel. I haven"t dug into why this works, but it seems like ToolStrip implements its own dragging behavior without using basic drag/drop functionality and by overriding OnBeginDragDrop
the ToolStrip is then using its custom behavior exclusively which makes the mouse act a lot nicer when dragging it.
回答2:
The toolstrip classes in Winforms are pretty quirky. They were released in .NET 2.0 and the Winforms team got disbanded pretty quickly after that. A lot of team members moved into the WPF project. Those quirks never got addressed as a result. There is very little you can do about this yourself, most of the toolstrip code is locked up without any way to override behavior. There's also rather a lot of it so rewriting is not practical either.
You can prevent the row from growing vertically. You do so by setting the MaximumSize property on the top toolstrip content panel:
public Form1() {
InitializeComponent();
toolStripContainer1.TopToolStripPanel.MaximumSize =
new Size(0, toolStrip1.Height);
}
But when you play around with this you'll find that this can make a toolstrip disappear entirely. No clean fix for that.
Do note that this is not exactly a real problem, the locations of the toolstrips are the user's choice and you should not help in any way. You can count on the user arranging them in a logical way.
回答3:
How about you suspend layout on OnMouseLeave, and re-enable it OnMouseEnter/OnMouseUp/etc?
public class ToolStripContainerFix : ToolStripContainer
{
public ToolStripContainerFix()
: base()
{
this.TopToolStripPanel.MouseLeave += TopToolStripPanel_MouseLeave;
this.TopToolStripPanel.MouseEnter += TopToolStripPanel_MouseEnter;
}
void TopToolStripPanel_MouseLeave(object sender, EventArgs e)
{
this.TopToolStripPanel.SuspendLayout();
}
void TopToolStripPanel_MouseEnter(object sender, EventArgs e)
{
this.TopToolStripPanel.ResumeLayout();
}
}
you would need to fiddle with this so that it checks its outside the form, rather than the control itself... that way you could allow new rows to be created when intended.
来源:https://stackoverflow.com/questions/15120432/moving-toolstrip-just-a-little-too-far-left-will-create-a-new-row-if-another-too