问题
Gretings.
I'm making an interface to edit scenarios for a game. Basically it consists of events, which have nested conditions and actions. So, i planned using two treeviews - one for selecting the event, and other for selecting the condition/action inside the event to edit.
Now, you see, if i select an event (in left treeview) and then try to select something in the right treeview, the left treeview will stop showing the blue selection rectangle. This is obviously bad because now the user doesnt know which event is he editing!
The only way i found to retain some sort of information about what is the current selection is by using SelectedImageIndex, but thats only one little image that will be different.
Is there any other way to highlight the treenode while there is no focus on the treeview? I know i can just Graphics.DrawRectangle or something, but i heard that drawing should be done in Paint event and treeview has no paint event... So i guess if i draw it on the event of losing focus, and then drag the form out of the screen or something, it will be "erased"?
Anyway, please tell me if you got an idea (other than using a separate icon for selected and not selected treenode)
Thanks!
回答1:
What you are looking for is the HideSelection
property on the TreeView
.
From MSDN:
Gets or sets a value indicating whether the selected tree node remains highlighted even when the tree view has lost the focus.
Link: http://msdn.microsoft.com/en-us/library/system.windows.forms.treeview.hideselection.aspx
Code:
TreeView.HideSelection = false;
回答2:
It is still shown but only in light grey which depending on your screen and current setup can be near in visible!
Override the OnDrawNode event. So you create and new class (call it "SpecialTreeView") an inherit from the Microsoft TreeView
like class SpecialTreeView : TreeView
. Then you add the following event override:
protected override void OnDrawNode(DrawTreeNodeEventArgs e)
{
TreeNodeStates treeState = e.State;
Font treeFont = e.Node.NodeFont ?? e.Node.TreeView.Font;
// Colors.
Color foreColor = e.Node.ForeColor;
string strDeselectedColor = @"#6B6E77", strSelectedColor = @"#94C7FC";
Color selectedColor = System.Drawing.ColorTranslator.FromHtml(strSelectedColor);
Color deselectedColor = System.Drawing.ColorTranslator.FromHtml(strDeselectedColor);
// New brush.
SolidBrush selectedTreeBrush = new SolidBrush(selectedColor);
SolidBrush deselectedTreeBrush = new SolidBrush(deselectedColor);
// Set default font color.
if (foreColor == Color.Empty)
foreColor = e.Node.TreeView.ForeColor;
// Draw bounding box and fill.
if (e.Node == e.Node.TreeView.SelectedNode)
{
// Use appropriate brush depending on if the tree has focus.
if (this.Focused)
{
foreColor = SystemColors.HighlightText;
e.Graphics.FillRectangle(selectedTreeBrush, e.Bounds);
ControlPaint.DrawFocusRectangle(e.Graphics, e.Bounds, foreColor, SystemColors.Highlight);
TextRenderer.DrawText(e.Graphics, e.Node.Text, treeFont, e.Bounds,
foreColor, TextFormatFlags.GlyphOverhangPadding);
}
else
{
foreColor = SystemColors.HighlightText;
e.Graphics.FillRectangle(deselectedTreeBrush, e.Bounds);
ControlPaint.DrawFocusRectangle(e.Graphics, e.Bounds, foreColor, SystemColors.Highlight);
TextRenderer.DrawText(e.Graphics, e.Node.Text, treeFont, e.Bounds,
foreColor, TextFormatFlags.GlyphOverhangPadding);
}
}
else
{
if ((e.State & TreeNodeStates.Hot) == TreeNodeStates.Hot)
{
e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds);
TextRenderer.DrawText(e.Graphics, e.Node.Text, hotFont, e.Bounds,
System.Drawing.Color.Black, TextFormatFlags.GlyphOverhangPadding);
}
else
{
e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds);
TextRenderer.DrawText(e.Graphics, e.Node.Text, treeFont, e.Bounds,
foreColor, TextFormatFlags.GlyphOverhangPadding);
}
}
}
Compile the code and you should see "SpecialTreeView" in your tool box in the designer. Replace your TreeView with this new one using the same name and the only thing that will be different is the selection colours. When selected it will be selectedColor
, when not selected the deselectedColor
.
I hope this helps.
回答3:
Fast solution:
Set the properties:
HideSelection = false;
DrawMode = TreeViewDrawMode.OwnerDrawText;
Then in the DrawNode event handler simply do:
private void treeView1_DrawNode(object sender, DrawTreeNodeEventArgs e) {
e.DrawDefault = true;
}
On Windwos 7 this restores the old rendering, including the dashed box around the selection (which actually looks a bit outdated). The text will be white with focus, and black without focus. The background stays blue and visible.
This answer is not new, the others also contain these steps, but this is the minimal needed (at least in Windows 7, didn't test other OS's).
回答4:
Not absolutely perfect solution, but quite near:
treeView.HideSelection = false;
treeView.DrawMode = TreeViewDrawMode.OwnerDrawText;
treeView.DrawNode += (o, e) =>
{
if (!e.Node.TreeView.Focused && e.Node == e.Node.TreeView.SelectedNode)
{
Font treeFont = e.Node.NodeFont ?? e.Node.TreeView.Font;
e.Graphics.FillRectangle(Brushes.Gray, e.Bounds);
ControlPaint.DrawFocusRectangle(e.Graphics, e.Bounds, SystemColors.HighlightText, SystemColors.Highlight);
TextRenderer.DrawText(e.Graphics, e.Node.Text, treeFont, e.Bounds, SystemColors.HighlightText, TextFormatFlags.GlyphOverhangPadding);
}
else
e.DrawDefault = true;
};
treeView.MouseDown += (o, e) =>
{
TreeNode node = treeView.GetNodeAt(e.X, e.Y);
if (node != null && node.Bounds.Contains(e.X, e.Y))
treeView.SelectedNode = node;
};
回答5:
Similar to the previous one but with the appearance more similar to the Win10 standard:
treeView.HideSelection = false;
treeView.DrawMode = TreeViewDrawMode.OwnerDrawText;
treeView.DrawNode += (o, e) =>
{
if (e.Node == e.Node.TreeView.SelectedNode)
{
Font font = e.Node.NodeFont ?? e.Node.TreeView.Font;
Rectangle r = e.Bounds;
r.Offset(0, 1);
Brush brush = e.Node.TreeView.Focused ? SystemBrushes.Highlight : Brushes.Gray;
e.Graphics.FillRectangle(brush, e.Bounds);
TextRenderer.DrawText(e.Graphics, e.Node.Text, font, r, SystemColors.HighlightText, TextFormatFlags.GlyphOverhangPadding);
}
else
e.DrawDefault = true;
};
treeView.MouseDown += (o, e) =>
{
TreeNode node = treeView.GetNodeAt(e.Location);
if (node != null && node.Bounds.Contains(e.Location)) treeView.SelectedNode = node;
};
回答6:
Found an easier way:
- Set TreeView.HideSelection = True
- Add the following to TreeView.AfterSelect-Callback:
private void treeViewBenutzerverwaltung_AfterSelect(object sender, TreeViewEventArgs e) { // Select new node e.Node.BackColor = SystemColors.Highlight; e.Node.ForeColor = SystemColors.HighlightText; if (_lastSelectedNode != null) { // Deselect old node _lastSelectedNode.BackColor = SystemColors.Window; _lastSelectedNode.ForeColor = SystemColors.WindowText; } lastSelectedNode = e.Node; }
来源:https://stackoverflow.com/questions/10034714/c-sharp-winforms-highlight-treenode-when-treeview-doesnt-have-focus