C#: Convert a tree node and sub nodes to text

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TreeToText
{
    class TreeToText
    {
        const string LineMid = "├─";
        const string LineLast = "└─";
        const string Line = "│  ";
        const string Space = "    ";

        /// <summary>
        /// Convert a tree node to text
        /// </summary>
        /// <param name="node">Root node to convert</param>
        /// <returns>Text</returns>
        public static string Tree2Text(TreeNode node)
        {
            if (node == null) return null;
            StringBuilder builder = new StringBuilder();
            builder.AppendLine(TreeNodeText(node));
            Tree2Text(builder, node, "");
            return builder.ToString();
        }

        static string TreeNodeText(TreeNode node)
        {
            return node.Text;
        }

        static void Tree2Text(StringBuilder builder, TreeNode parent, string prefix)
        {
            int nodesCount = parent.Nodes.Count;
            if (nodesCount == 0) return;
            int nodeMaxIndex = nodesCount - 1;
            for (int i = 0; i < nodesCount; i++)
            {
                builder.Append(prefix);
                TreeNode node = parent.Nodes[i];
                if (i != nodeMaxIndex)
                {
                    builder.Append(LineMid);
                    builder.AppendLine(TreeNodeText(node));
                    Tree2Text(builder, node, prefix + Line);
                }
                else
                {
                    builder.Append(LineLast);
                    builder.AppendLine(TreeNodeText(node));
                    Tree2Text(builder, node, prefix + Space);
                }
            }
        }
    }
}

中国IP地址段抽取工具

本工具可以将所有中国的IP v4地址段抽取出来,并按照用户给定的格式保存。
通常可以用于制作特定的路由表。

IP信息来源:每次运行时自动获取自APNIC。
运行需要:dotnet Framework 4.0

运行前,请用文本编辑器打开CNRouteExtractor.exe.config,按照注释修改其中的Format字符串。
运行时的格式:CNRouteExtractor filename
将生成filename作为目标输出文件。如不指定filename则不输出(仅测试下载与抽取)。

下载地址

C#: Split a Distinguished Name of Active Directory into array of string

class DistinguishedNameSplit
{
    static string[] hexCodes = new string[] { "0""1""2""3""4""5""6""7""8""9""a""A""b""B""c""C""d""D""e""E""f""F" };
 
    public static List<string> Split(string distinguishedName)
    {
        List<string> pool = new List<string>();
        StringBuilder working = new StringBuilder();
        string hexHigh = "";
        MachineStatus status = MachineStatus.A;
        int index = 0;
        int indexMax = distinguishedName.Length - 1;
 
        while (index <= indexMax)
        {
            string value = distinguishedName.Substring(index, 1);
            switch (status)
            {
                case MachineStatus.A:
                    if (value == ",")
                    {
                        pool.Add(working.ToString());
                        working.Clear();
                    }
                    else if (value == "\"")
                    {
                        working.Append("\"");
                        status = MachineStatus.B;
                    }
                    else if (value == "\\")
                    {
                        status = MachineStatus.C;
                    }
                    else
                    {
                        working.Append(value);
                    }
                    break;
                case MachineStatus.B:
                    if (value == "\"")
                    {
                        working.Append("\"");
                        status = MachineStatus.A;
                    }
                    else if (value == "\\")
                    {
                        status = MachineStatus.E;
                    }
                    else
                    {
                        working.Append(value);
                    }
                    break;
                case MachineStatus.C:
                    if (value == "," || value == "\"" || value == "\\")
                    {
                        working.Append(value);
                        status = MachineStatus.A;
                    }
                    else if (hexCodes.Contains(value))
                    {
                        hexHigh = value;
                        status = MachineStatus.D;
                    }
                    else
                    {
                        throw new ArgumentException("The distinguished name specified is not typed legally.");
                    }
                    break;
                case MachineStatus.D:
                    if (hexCodes.Contains(value))
                    {
                        working.Append((char)Convert.ToByte(String.Format("{0}{1}", hexHigh, value), 16));
                        status = MachineStatus.A;
                    }
                    else
                    {
                        throw new ArgumentException("The distinguished name specified is not typed legally.");
                    }
                    break;
                case MachineStatus.E:
                    if (value == "," || value == "\"" || value == "\\")
                    {
                        working.Append(value);
                        status = MachineStatus.B;
                    }
                    else if (hexCodes.Contains(value))
                    {
                        hexHigh = value;
                        status = MachineStatus.F;
                    }
                    else
                    {
                        throw new ArgumentException("The distinguished name specified is not typed legally.");
                    }
                    break;
                case MachineStatus.F:
                    if (hexCodes.Contains(value))
                    {
                        working.Append((char)Convert.ToByte(String.Format("{0}{1}", hexHigh, value), 16));
                        status = MachineStatus.B;
                    }
                    else
                    {
                        throw new ArgumentException("The distinguished name specified is not typed legally.");
                    }
                    break;
            }
            index++;
        }
 
        if (status == MachineStatus.A)
        {
            pool.Add(working.ToString());
            return pool;
        }
        else
        {
            throw new ArgumentException("The distinguished name specified is not ended correctly.");
        }
    }
 
    enum MachineStatus
    {
        A, B, C, D, E, F
    }
}

Recursive Enumerator

using System;
using System.Collections.Generic;

namespace SecretNest.RecursiveEnumerator
{
    /// <summary>
    /// Get the enumerator for querying the parents of specified item.
    /// </summary>
    /// <typeparam name="T">Item type</typeparam>
    /// <param name="current">Item for querying parents</param>
    /// <returns>Enumerator of parents querying</returns>
    public delegate IEnumerator<T> GetParentsEnumerator<T>(T current);

    /// <summary>
    /// Enumerator for querying parents
    /// </summary>
    /// <typeparam name="T">Item type</typeparam>
    public class Enumerator<T> : IEnumerator<T>
    {
        T current, initial;

        Queue<T> notQueried = new Queue<T>();

        HashSet<T> queried = new HashSet<T>(); //for avoiding duplicated query
        Queue<T> rollbackHistory = new Queue<T>(); //for soft reset
        Queue<T> history = new Queue<T>(); //for soft reset
        IEnumerator<T> activeQuery;

        /// <summary>
        /// Callback for getting the enumerator, which is used for querying the parents of specified item.
        /// </summary>
        public GetParentsEnumerator<T> GetParentsEnumeratorCallback { get; set; }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="initial">Initial item</param>
        public Enumerator(T initial)
        {
            notQueried.Enqueue(initial);
            this.initial = initial;
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="initial">Initial item</param>
        /// <param name="callback">Callback for getting the enumerator, which is used for querying the parents of specified item.</param>
        public Enumerator(T initial, GetParentsEnumerator<T> callback)
        {
            notQueried.Enqueue(initial);
            this.initial = initial;
            GetParentsEnumeratorCallback = callback;
        }

        /// <summary>
        /// Gets the current element in the collection.
        /// </summary>
        public T Current
        {
            get { return current; }
        }

        bool disposed;
        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    current = default(T);
                    notQueried = null;
                    queried = null;
                    history = null;
                }
                disposed = true;
            }
        }

        /// <summary>
        /// Gets the current element in the collection.
        /// </summary>
        object System.Collections.IEnumerator.Current
        {
            get { return current; }
        }

        /// <summary>
        /// Skip same items
        /// </summary>
        public bool SkipSameItems { get; set; }

        /// <summary>
        /// Advances the enumerator to the next element of the collection.
        /// </summary>
        /// <returns>true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection. </returns>
        public bool MoveNext()
        {
            if (disposed) throw new ObjectDisposedException(null);
            if (rollbackHistory.Count > 0)
            {
                current = rollbackHistory.Dequeue();
                history.Enqueue(current);
                return true;
            }
            if (activeQuery != null)
            {
            here:
                if (activeQuery.MoveNext())
                {
                    if (SkipSameItems && history.Contains(activeQuery.Current)) { goto here; }
                    current = activeQuery.Current;
                    history.Enqueue(current);
                    notQueried.Enqueue(current);
                    return true;
                }
                else
                {
                    activeQuery = null;
                }
            }
            if (GetParentsEnumeratorCallback != null)
            {
                while (notQueried.Count != 0)
                {
                    T item = notQueried.Dequeue();
                    if (!queried.Contains(item))
                    {
                        IEnumerator<T> enumerator = GetParentsEnumeratorCallback(item);
                        queried.Add(item);
                        here:
                        if (enumerator != null)
                        {
                            if (enumerator.MoveNext())
                            {
                                activeQuery = enumerator;
                                if (SkipSameItems && history.Contains(enumerator.Current)) { goto here; }
                                current = enumerator.Current;
                                history.Enqueue(current);
                                notQueried.Enqueue(current);
                                return true;
                            }
                            else
                            {
                                enumerator = null;
                            }
                        }
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// Sets the enumerator to its initial position, which is before the first element in the collection. Keep all histories for caching.
        /// </summary>
        public void Reset()
        {
            if (disposed) throw new ObjectDisposedException(null);
            while (history.Count > 0)
            {
                rollbackHistory.Enqueue(history.Dequeue());
            }
            current = default(T);
        }

        /// <summary>
        /// Sets the enumerator to its initial position, which is before the first element in the collection. Reset all data, and close active sub-query.
        /// </summary>
        public void HardReset()
        {
            if (disposed) throw new ObjectDisposedException(null);
            queried.Clear();
            notQueried.Clear();
            notQueried.Enqueue(initial);
            history.Clear();
            activeQuery = null;
            current = default(T);
        }
    }
}

Download code and demo projects

TreeView with CheckBox

If you wanna use CheckBox enabled TreeView in Windows Vista and further systems, you need to pay attention. If you double click the CheckBoxes in the TreeView, some useful event handlers, like BeforeClick and AfterClick, will not be raised. And, the vision of CheckBoxes will be changed (checked or not) but the property of related TreeNode will not.

To fix this, you have to create your own TreeView instead of the provided one.

using System;
using System.Windows.Forms;

[
        ComVisible(true),
        ClassInterface(ClassInterfaceType.AutoDispatch),
        DefaultProperty("Nodes"),
        DefaultEvent("AfterSelect"),
        Docking(DockingBehavior.Ask),
        Designer("System.Windows.Forms.Design.TreeViewDesigner"),
]
public class FixedTreeView : TreeView
{
	protected override void WndProc(ref Message m)
	{
		// Suppress WM_LBUTTONDBLCLK
		if (m.Msg == 0x203)
		{
			m.Result = IntPtr.Zero;
		}
		else
		{
			base.WndProc(ref m);
		}
	}
}

Source: http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/9d717ce0-ec6b-4758-a357-6bb55591f956