Custom TreeView class displays unwanted characters

2019-09-21 01:12发布

I have created a custom TreeView class. I have a display problem when opening and closing the top nodes in that characters appears in the first column. First the tree is displayed:

enter image description here
Then after opening and closing the top nodes, unwanted characters appear in the first column:

enter image description here

What is the problem?

public class CustomTreeView : TreeView
{
    public CustomTreeView() : base()
    {
        this.SetStyle(
            ControlStyles.UserPaint |
            ControlStyles.DoubleBuffer |
            ControlStyles.Opaque, true);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        using (System.Drawing.SolidBrush BackGroundBrush = new System.Drawing.SolidBrush(System.Drawing.SystemColors.Window))
        using (System.Drawing.SolidBrush ForeGroundBrush = new System.Drawing.SolidBrush(System.Drawing.SystemColors.WindowText))
        using (System.Drawing.SolidBrush BackGroundBrushHighLight = new System.Drawing.SolidBrush(System.Drawing.Color.DarkGreen))
        using (System.Drawing.SolidBrush ForeGroundBrushHighLight = new System.Drawing.SolidBrush(System.Drawing.Color.Pink))
        {
            e.Graphics.FillRectangle(BackGroundBrush, e.ClipRectangle);
            System.Drawing.SolidBrush CurrentNode;

            int count = this.Nodes.Count;
            System.Diagnostics.Trace.WriteLine("CustomTreeView.OnPaint: count: " + count);
            for (int topLevelIndex = 0; topLevelIndex < count; ++topLevelIndex)
            {
                TreeNode topLevelTreeNode = Nodes[topLevelIndex];
                CurrentNode = ForeGroundBrush; // top level always this, never selected
                e.Graphics.DrawString(topLevelTreeNode.Text, this.Font, CurrentNode, Rectangle.Inflate(topLevelTreeNode.Bounds, 2, 0));

                int nodeCount = topLevelTreeNode.GetNodeCount(true);
                System.Diagnostics.Trace.WriteLine("CustomTreeView.OnPaint: Nodes[index].GetNodeCount: " + nodeCount);

                foreach (TreeNode childNode in topLevelTreeNode.Nodes)
                {
                    if (childNode.IsSelected)
                    {
                        CurrentNode = ForeGroundBrushHighLight;
                        e.Graphics.FillRectangle(BackGroundBrushHighLight, childNode.Bounds);
                    }
                    else
                    {
                        CurrentNode = ForeGroundBrush;
                    }
                    e.Graphics.DrawString(childNode.Text, this.Font, CurrentNode, Rectangle.Inflate(childNode.Bounds, 2, 0));
                }
            }

        }
    }
}

class ProjectConstants
{
    public const string TOP_NODE_CLASSICAL = "Classical";
    public const string TOP_NODE_JAZZ = "Jazz";
    public const string TOP_NODE_ROCK = "Rock";

    public const string CLASSICAL_BEETHOVEN = "Beethoven";
    public const string CLASSICAL_MOZART = "Mozart";
    public const string CLASSICAL_CHOPIN = "Chopin";

    public const string JAZZ_MONK = "Thelonius Monk";
    public const string JAZZ_MINGUS = "Charles Mingus";
    public const string JAZZ_COLTRANE = "John Coltrane";

    public const string ROCK_CORNELL = "Chris Cornell";
    public const string ROCK_PLANT = "Robert Plant";
    public const string ROCK_SPRINGSTEEN = "Bruce Springsteen";
}

partial class TreeViewDialog
{
    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Windows Form Designer generated code

    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        this.components = new System.ComponentModel.Container();
        System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TreeViewDialog));
        this.btnSave = new System.Windows.Forms.Button();
        this.btnCancel = new System.Windows.Forms.Button();
        this.bMusicDocumentType = new System.Windows.Forms.BindingSource(this.components);
        this.treeView = new Views.Project.CustomTreeView();
        ((System.ComponentModel.ISupportInitialize)(this.bMusicDocumentType)).BeginInit();
        this.SuspendLayout();
        // 
        // btnSave
        // 
        this.btnSave.Location = new System.Drawing.Point(227, 345);
        this.btnSave.Name = "btnSave";
        this.btnSave.Size = new System.Drawing.Size(75, 23);
        this.btnSave.TabIndex = 6;
        this.btnSave.Text = "Save    ";
        this.btnSave.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
        this.btnSave.UseVisualStyleBackColor = true;
        this.btnSave.Click += new System.EventHandler(this.btnSave_Click);
        // 
        // btnCancel
        // 
        this.btnCancel.Location = new System.Drawing.Point(12, 345);
        this.btnCancel.Name = "btnCancel";
        this.btnCancel.Size = new System.Drawing.Size(75, 23);
        this.btnCancel.TabIndex = 7;
        this.btnCancel.Text = "Cancel  ";
        this.btnCancel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
        this.btnCancel.UseVisualStyleBackColor = true;
        this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
        // 
        // bMusicDocumentType
        // 
        this.bMusicDocumentType.DataSource = ((object)(resources.GetObject("bMusicDocumentType.DataSource")));
        this.bMusicDocumentType.Position = 0;
        // 
        // treeView
        // 
        this.treeView.HideSelection = false;
        this.treeView.Location = new System.Drawing.Point(15, 12);
        this.treeView.Name = "treeView";
        this.treeView.Size = new System.Drawing.Size(287, 303);
        this.treeView.TabIndex = 14;
        this.treeView.BeforeSelect += new System.Windows.Forms.TreeViewCancelEventHandler(this.treeViewCategoryType_BeforeSelect);
        this.treeView.NodeMouseClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.treeViewCategoryType_TreeNodeMouseClickEventHandler);
        // 
        // TreeViewDialog
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(330, 392);
        this.Controls.Add(this.treeView);
        this.Controls.Add(this.btnCancel);
        this.Controls.Add(this.btnSave);
        this.Name = "TreeViewDialog";
        this.Text = "New Music";
        ((System.ComponentModel.ISupportInitialize)(this.bMusicDocumentType)).EndInit();
        this.ResumeLayout(false);

    }

    #endregion
    private System.Windows.Forms.Button btnSave;
    private System.Windows.Forms.Button btnCancel;
    private System.Windows.Forms.BindingSource bMusicDocumentType;
    private Views.Project.CustomTreeView treeView;
}

public partial class TreeViewDialog : Form
{
    // Create a Font object for the node tags.
    private Font tagFont = new Font("Helvetica", 8, FontStyle.Bold);

    public static List<String> musicList = new List<String>(new string[] {
        //ProjectConstants.TOP_NODE_CLASSICAL,
        ProjectConstants.CLASSICAL_BEETHOVEN,
        ProjectConstants.CLASSICAL_MOZART,
        ProjectConstants.CLASSICAL_CHOPIN,
        //ProjectConstants.TOP_NODE_JAZZ,
        ProjectConstants.JAZZ_MONK,
        ProjectConstants.JAZZ_MINGUS,
        ProjectConstants.JAZZ_COLTRANE,
        //ProjectConstants.TOP_NODE_ROCK,
        ProjectConstants.ROCK_CORNELL,
        ProjectConstants.ROCK_PLANT,
        ProjectConstants.ROCK_SPRINGSTEEN,
        });

    //  Add unselectable nodes to this collection when you create them
    private List<TreeNode> _unselectableNodes = new List<TreeNode>();

    public TreeViewDialog (String documentType)
    {

        InitializeComponent();

        this.treeView.Update();

        // Add (key, text), where key is name of the tree node and text is the text to display
        TreeNode treeNodeClassical = this.treeView.Nodes.Add(ProjectConstants.TOP_NODE_CLASSICAL, ProjectConstants.TOP_NODE_CLASSICAL);
        treeNodeClassical.Tag = ProjectConstants.TOP_NODE_CLASSICAL;
        _unselectableNodes.Add(treeNodeClassical);

        TreeNode treeNode = treeNodeClassical.Nodes.Add(ProjectConstants.CLASSICAL_BEETHOVEN, ProjectConstants.CLASSICAL_BEETHOVEN);
        treeNode.Tag = ProjectConstants.CLASSICAL_BEETHOVEN;
        treeNode = treeNodeClassical.Nodes.Add(ProjectConstants.CLASSICAL_MOZART, ProjectConstants.CLASSICAL_MOZART);
        treeNode.Tag = ProjectConstants.CLASSICAL_MOZART;
        treeNode = treeNodeClassical.Nodes.Add(ProjectConstants.CLASSICAL_CHOPIN, ProjectConstants.CLASSICAL_CHOPIN);
        treeNode.Tag = ProjectConstants.CLASSICAL_CHOPIN;

        TreeNode treeNodeJazz = this.treeView.Nodes.Add(ProjectConstants.TOP_NODE_JAZZ, ProjectConstants.TOP_NODE_JAZZ);
        treeNodeJazz.Tag = ProjectConstants.TOP_NODE_JAZZ;
        _unselectableNodes.Add(treeNodeJazz);

        treeNode = treeNodeJazz.Nodes.Add(ProjectConstants.JAZZ_MONK, ProjectConstants.JAZZ_MONK);
        treeNode.Tag = ProjectConstants.JAZZ_MONK;
        treeNode = treeNodeJazz.Nodes.Add(ProjectConstants.JAZZ_MINGUS, ProjectConstants.JAZZ_MINGUS);
        treeNode.Tag = ProjectConstants.JAZZ_MINGUS;
        treeNode = treeNodeJazz.Nodes.Add(ProjectConstants.JAZZ_COLTRANE, ProjectConstants.JAZZ_COLTRANE);
        treeNode.Tag = ProjectConstants.JAZZ_COLTRANE;

        TreeNode treeNodeRock = this.treeView.Nodes.Add(ProjectConstants.TOP_NODE_ROCK, ProjectConstants.TOP_NODE_ROCK);
        treeNodeRock.Tag = ProjectConstants.TOP_NODE_ROCK;
        _unselectableNodes.Add(treeNodeRock);

        treeNode = treeNodeRock.Nodes.Add(ProjectConstants.ROCK_CORNELL, ProjectConstants.ROCK_CORNELL);
        treeNode.Tag = ProjectConstants.ROCK_CORNELL;
        treeNode = treeNodeRock.Nodes.Add(ProjectConstants.ROCK_PLANT, ProjectConstants.ROCK_PLANT);
        treeNode.Tag = ProjectConstants.ROCK_PLANT;
        treeNode = treeNodeRock.Nodes.Add(ProjectConstants.ROCK_SPRINGSTEEN, ProjectConstants.ROCK_SPRINGSTEEN);
        treeNode.Tag = ProjectConstants.ROCK_SPRINGSTEEN;

        this.treeView.ExpandAll();

        // if something was selected on the tab page, then select it here
        if (!String.IsNullOrEmpty(documentType))
        {
            TreeNode namedNode = null;
            foreach (TreeNode node in treeView.Nodes)
            {
                namedNode = getTreeNodeFromName(documentType, node);
                if (namedNode != null)
                {
                    break; // nothing found
                }
            }

            if (namedNode != null)
            {
                treeView.SelectedNode = namedNode; 
            }
            treeView.Focus();

        }

        this.treeView.EndUpdate();
    }

    public TreeNode getTreeNodeFromName(string name, TreeNode rootNode)
    {
        foreach (TreeNode node in rootNode.Nodes)
        {
            if (node.Name.Equals(name))
            {
                return node;
            }
            TreeNode next = getTreeNodeFromName(name, node);
            if (next != null)
            {
                return next;
            }
        }
        return null;
    }

    private void btnSave_Click(object sender, EventArgs e)
    {
        // nothing right now
    }


    private void btnCancel_Click(object sender, EventArgs e)
    {
        this.Close();
    }

    private void treeViewCategoryType_TreeNodeMouseClickEventHandler(object sender, TreeNodeMouseClickEventArgs eventArgs)
    {            TreeView treeView = (TreeView)sender;

        TreeNode treeNode = eventArgs.Node; // parent or child

        String nodeText = treeNode.Text;

        // if parent treeNode
        if (nodeText.Equals(ProjectConstants.TOP_NODE_CLASSICAL) ||
            nodeText.Equals(ProjectConstants.TOP_NODE_JAZZ) ||
            nodeText.Equals(ProjectConstants.TOP_NODE_ROCK))
        {
            // don't select the treeNode
        }
        else
        {  // child
        }

    }

    private void treeViewCategoryType_BeforeSelect(object sender, TreeViewCancelEventArgs eventArgs)
    {
        if (_unselectableNodes.Contains(eventArgs.Node))
        {
            eventArgs.Cancel = true;
        }
    }
}

1条回答
小情绪 Triste *
2楼-- · 2019-09-21 01:47

You are drawing the texts too many times, you should also check if the child node's parent is expanded, otherwise you don't need to DrawString in your loop to execute. Change you code like this at onPaint event,

if(childNode.IsSelected)
{
     CurrentNode = ForeGroundBrushHighLight;
     e.Graphics.FillRectangle(BackGroundBrushHighLight, childNode.Bounds);
}
else
{
     CurrentNode = ForeGroundBrush;
}
if(childNode.Parent.IsExpanded)
{
     e.Graphics.DrawString(childNode.Text, this.Font, CurrentNode, Rectangle.Inflate(childNode.Bounds, 2, 0));
}

Hope helps,

查看更多
登录 后发表回答