TreeView Node rekursiv über String suchen

/// <summary->
/// sucht TreeNode rekursiv
/// </summary->
/// <param name=&quot;n&quot;->StartNode</param->
/// <param name=&quot;txt&quot;->Suchtext</param->
/// <returns->gefundene TreeNode oder null</returns->
public TreeNode FindNode(TreeNode n, string txt)
{
    TreeNode r = null;

    foreach (TreeNode tn in n.Nodes)
    {
        if (tn.Text == txt)
        {
            r = tn;
            break;
        }

        r = FindNode(tn, txt);

        if (r != null) break;
    }

    return r;
}

Generische Listenklasse mit Indexer und Enumerator

using System;
using System.Collections;
using System.Collections.Generic;
/// <summary>
/// generic list class with indexer and enumerator
/// freeware 2011 by admin of codezentrale.6x.to
/// </summary>
/// <typeparam name="T">datatype you want to manage</typeparam>
public class GenericList<T> : IEnumerable, IDisposable
{
    /// <summary>
    /// internal class, with interface for IEnumerable and IEnumerator
    /// </summary>
    private class GenericListEnumerator : IEnumerator
    {
        private int pos = -1;
        private GenericList<T> _t;

        public GenericListEnumerator(GenericList<T> t)
        {
            this._t = t;
        }

        public bool MoveNext()
        {
            if (pos < _t.Count - 1)
            {
                pos++;
                return true;
            }
            else
            {
                return false;
            }
        }

        public void Reset()
        {
            pos = -1;
        }

        public object Current
        {
            get
            {
                try
                {
                    return _t[pos];
                }
                catch (IndexOutOfRangeException)
                {
                    throw new InvalidOperationException();
                }
            }
        }
    }

    private List<T> _ObjectList = new List<T>();
    private bool _bDisposed = false;

    /// <summary>
    /// object counter
    /// </summary>
    public int Count
    {
        get { return _ObjectList.Count; }
    }
    /// <summary>
    /// indexer for direct index based access (e.g. mylist[1])
    /// </summary>
    /// <param name="pos"></param>
    /// <returns></returns>
    public T this[int pos]
    {
        get { return _ObjectList[pos]; }
        set { _ObjectList[pos] = value; }
    }

    public GenericList()
    {
    }

    // destructor, makro for 'protected override void Finalize()'
    ~GenericList()
    {
        this.Dispose(false);
    }

    // public Dispose-method for cleanup
    public void Dispose()
    {
        this.Dispose(true);
    }

    // internal Dispose-method
    private void Dispose(bool bDisposing)
    {
        if (!_bDisposed)
        {
            if (bDisposing)
            {
                // e.g. free managed resources here
            }
        }

        _bDisposed = true;
    }

    /// <summary>
    /// interface function for IEnumerable and IEnumerator
    /// </summary>
    /// <returns></returns>
    public IEnumerator GetEnumerator()
    {
        return new GenericListEnumerator(this);
    }
    /// <summary>
    /// add object to list
    /// </summary>
    /// <param name="obj">your object</param>
    public void Add(T obj)
    {
        _ObjectList.Add(obj);
    }
    /// <summary>
    /// clear list
    /// </summary>
    public void Clear()
    {
        _ObjectList.Clear();
    }
    /// <summary>
    /// swap objects inside list
    /// </summary>
    /// <param name="index1">index number one</param>
    /// <param name="index2">index number one</param>
    public void Swap(int index1, int index2)
    {
        if ((index1 >= 0) && (index2 >= 0) && (index1 < _ObjectList.Count) && (index2 < _ObjectList.Count))
        {
            T temp = _ObjectList[index1];
            _ObjectList[index1] = _ObjectList[index2];
            _ObjectList[index2] = temp;
        }
    }
    /// <summary>
    /// remove object from list
    /// </summary>
    /// <param name="obj"></param>
    public void Remove(T obj)
    {
        _ObjectList.Remove(obj);
    }
}

RichTextBox Text einfärben

private void InsertColoredText(string txt, Color col)
{
    int pos = rtb.TextLength;
    string s = txt + Environment.NewLine;

    rtbTestStatus.AppendText(s);
    rtbTestStatus.Select(pos, s.Length);
    rtbTestStatus.SelectionColor = col;
    rtbTestStatus.DeselectAll();            
}

StringBuilder verwenden

using System.Text; 

StringBuilder sb = new StringBuilder();
// Zeichen anhängen
sb.Append("Hans" + Environment.NewLine);
// Zeile anhägen
sb.AppendLine("Hilde");
// Zeichen einfügen
strB.Insert(0, "Udo");
// Zeichen ersetzen
strBuilder = strBuilder.Replace("Hans", "Horst");
// Zugriff auf die gesamte Zeichenfolge
Console.WriteLine(sb.ToString());
// Zeichen löschen
sb.Remove(0, sb.Length);
oder
sb.Length = 0;
oder
sb.Clear(); // ab .NET 4.0

UpDown-Button in einer ListView-Zelle (SubItem) anzeigen

Der UpDown-Button muss zur Designzeit auf dem Listview vorhanden sein!

// Eigenschaften des UpDownButtons setzen
UDBtn.BorderStyle = BorderStyle.None;
UDBtn.Visible = false;
UDBtn.ValueChanged += new System.EventHandler(UDBtn_ValueChanged);

// Ereignis ItemSelectionChanged des ListViews behandeln
private void ListView1_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
{
    if (e.IsSelected)
    {
        this.SetBtn(e.Item);
        UDBtn.Visible = true;
    }
    else
    {
        UDBtn.Visible = false;
        e.Item.SubItems[ListView1.Columns.Count - 1].Text = UDBtn.Value.ToString();
    }
}

// Funktion setzt den Button in die akt. Zeile und jeweils letzte Spalte (ListView1.Columns.Count - 1) des ListViews
// Werte für X- und Y-Offset müssen ggf. Angepasst werden
private void SetBtn(ListViewItem lvi)
{
    int iLeft = 0;

    if (lvi != null)
    {
        if (lvi.Selected)
        {
            // adjust position values here, to fit correctly
            UDBtn.Top = 38 + lvi.Position.Y - 20;

            for (int iCol = 0; iCol < ListView1.Columns.Count; iCol++)
            {
                iLeft += ListView1.Columns&#91;iCol&#93;.Width;
            }

            UDBtn.Left = iLeft - 39;
            UDBtn.Width = ListView1.Columns&#91;ListView1.Columns.Count - 1&#93;.Width - 1;
            UDBtn.Value = decimal.Parse(lvi.SubItems&#91;ListView1.Columns.Count - 1&#93;.Text);
        }
    }
    else
    {
        UDBtn.Visible = false;
    }
}

// Ereignis ValueChanged des Buttons
private void UDBtn_ValueChanged(object sender, System.EventArgs e)
{
    ListViewItem lvi = (ListView1.SelectedItems.Count -> 0) ? lvi = ListView1.SelectedItems[0] : null;

    if (lvi != null)
    {
        lvi.SubItems[ListView1.Columns.Count - 1].Text = UDBtn.Value.ToString();
    }
}

Verhindern, dass TreeNode bei Rechtsklick deselektiert wird

Oft kommt es vor, dass man in einem TreeView eine TreeNode per Rechtsklick selektiert, zum Beispiel beim gleichzeitigen Anzeigen eines ContextMenueStrips. Dabei “schnappt” meist die Auswahl wieder auf die zuvor ausgewählte TreeNode zurück und das falsche Element ist gewählt. Um das zu verhindern muss man folgenden Code implementieren:

private void TreeView1_MouseUp(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Right)
    {
        TreeNode tnd = TreeView1.GetNodeAt(e.X, e.Y);
        if (tnd != null)
        {
            TreeView1.SelectedNode = tnd;
        }
    }
}

Stringliterale in Hexcodes wandeln

/// Beim Speichern von Strings in Textdateien möchte man manchmal, dass Literale (Zeilenumbrüche, Tabs usw.)
/// nicht interpretiert werden, sondern als hexadezimale Codierungen gespeichert werden.
/// die statische Klasse wandelt alle ASCII-Steuerzeichen in einem String mit ASCIICode < 32 in die entsprechenden hexadezimalen Pendants um.
using System;

/// <summary>
/// freeware helper class for converting string formats
/// (W) 2011 by admin of codezentrale.6x.to
/// </summary>
public static class StringConverter
{
    /// <summary>
    /// hex replace of literals
    /// </summary>
    /// <param name="path">a string</param>
    /// <returns>string with replaced literals</returns>
    public static string ReplaceLiterals(string inputstring)
    {
        string output = string.Empty;
        
        foreach (char t in inputstring)
        {
            int ascii = Convert.ToInt32(t);
            output += (ascii < 32) ? string.Format("&#x{0:X02};", ascii) : t.ToString();
        }

        return output;
    }
}

Beispiel:

string sInput = "Hallo" + Environment.NewLine + "Welt!"

// "Hallo Welt!"
string sOutPut = StringConverter.ReplaceLiterals(sInput));

Fließkommazahl kulturunabhängig in einen String wandeln

Speichert man Fließkommazahlen auf unterschiedlichen Systemen als String ab, kommt es vor, dass diese kulturabhängig formatiert werden. Beim Parsen solcher Strings treten dann Fehler auf, weil das System z.B. nicht mit dem Decimalseparator klarkommt.

Das Problem kann man umgehen, indem man die Strings mittels CultureInfo.InvariantCulture umwandelt:

double v = 3.14;

string value = v.ToString(CultureInfo.InvariantCulture); // value == "3.14"

Das Einlesen muss dann ebenfalls über CultureInfo.InvariantCulture erfolgen:

string value = "3.14";
double dValue = 0.0;
if (double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out dValue))
{
    ...
}

Universeller Eingabedialog, ähnlich Borland Delphi InputQuery

  • Anwendungsbeispiele
// einfacher string input
string currentvalue = "test";

InputQuery iq = new InputQuery();
if (iq.ShowDlg("Please type something", "Value:", ref currentvalue, false, 32))
{
    string newval = currentvalue;
}

// einfacher floating point input
string currentvalue = "3.14";

InputQuery iq = new InputQuery();
if (iq.ShowDlg("Please type something", "Value:", ref currentvalue, true, -1))
{
    double newval = double.Parse(currentvalue);
}
  • Quellcode des Dialoges:
// Objekte und deren Eigenschaften, die sich auf dem Formular befinden müssen:
//
// lblValue - ein Label, welches vor der TextBox als Bezeichner steht
// tbValue - eine TextBox zur Eingabe
// tbValue.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.tbValue_KeyPress);
// btnOk - OK-Button
// btnOk.DialogResult = System.Windows.Forms.DialogResult.OK;
// btnCancel - Abbrechen-Button
// btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
// this.AcceptButton = this.btnOk;
// this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
// this.Name = "InputQuery";

using System.Globalization;
using System.Windows.Forms;

/// <summary->
/// freeware helper class for recreating Borland Deplhi InputQuery-Dialog
/// (W) 2011 by admin of codezentrale.6x.to
/// </summary->
public partial class InputQuery : Form
{
    private const int MAX_TEXTBOX_STR_LENGTH = 32767;
    private string ALLOWED_FP_INPUT_CHARS = "0123456789" + NumberFormatInfo.CurrentInfo.NumberDecimalSeparator + "\b";
    private bool _checkdouble = false;

    public InputQuery()
    {
        InitializeComponent();
    }
    /// <summary->
    /// Shows a little input-dialog
    /// </summary->
    /// <param name="dlgcaption"->dialog caption</param->
    /// <param name="lbl"->label text</param->
    /// <param name="value"->input value</param->
    /// <param name="checkdouble"->if input is a floating-point, check for correct format and decimalseparator</param->
    /// <param name="maxstringlength"->if input is a regular string, set maxlenght here, otherwise "-1"</param->
    /// <returns->true if button 'Ok' is pressed</returns->
    public bool ShowDlg(string dlgcaption, string lbl, ref string value, bool checkdouble, int maxstringlength)
    {
        lblValue.Text = lbl;
        this.Text = dlgcaption;
        tbValue.Text = value;
        _checkdouble = checkdouble;
        tbValue.MaxLength = checkdouble ? MAX_TEXTBOX_STR_LENGTH : maxstringlength -> 0 ? maxstringlength : MAX_TEXTBOX_STR_LENGTH;
        tbValue.SelectAll();
        DialogResult blOk = this.ShowDialog();
        value = tbValue.Text;
        return (blOk == DialogResult.OK);
    }

    private void tbValue_KeyPress(object sender, KeyPressEventArgs e)
    {
        if (e.KeyChar == (char)(int)Keys.Enter)
        {
            this.DialogResult = DialogResult.OK;
        }
        else
            if (_checkdouble)
            {
                if (sender is TextBox)
                {
                    bool bNoDS = true;
                    TextBox tb = sender as TextBox;

                    if (e.KeyChar.ToString() == NumberFormatInfo.CurrentInfo.NumberDecimalSeparator)
                    {
                        bNoDS = (tb.Text.IndexOf(NumberFormatInfo.CurrentInfo.NumberDecimalSeparator) < 0);
                    }

                    if (bNoDS)
                    {
                        e.Handled = (ALLOWED_FP_INPUT_CHARS.IndexOf(e.KeyChar) < 0);
                    }
                    else
                    {
                        e.Handled = true;
                    }
                }
            }
    }
}

Eigene Textformatierungen und Bitmaps im ListView darstellen (OwnerDraw)

ListView1.OwnerDraw = true;
ListView1.View = View.Details;

// ListView-Überschriften zeichnen
private void ListView1_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
{
    e.DrawBackground();

    StringFormat sf = new StringFormat();
    sf.Alignment = StringAlignment.Center;

    // da StringAlignment.Center, muss die Breite für die Darstellung durch 2 geteilt werden
    int iWidth = ListView1.Columns[e.ColumnIndex].Width / 2;
    
    // Header-String zentriert, schwarz und fett zeichnen
    e.Graphics.DrawString(e.Header.Text, new Font("Microsoft Sans Serif", 8.25F, FontStyle.Bold), Brushes.Black, e.Bounds.X + iWidth, e.Bounds.Y, sf);
}

// ListView-Subitems zeichnen
private void ListView1_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
{
    StringFormat sf = new StringFormat();
    sf.Alignment = StringAlignment.Center;

    switch (e.ColumnIndex)
    {
        case 0:
            // Subitem 0 beinhaltet ein Bitmap
            Bitmap b = new Bitmap(@"c:\temp\test.jpg");
            e.Graphics.DrawImage(b, e.Bounds.X, e.Bounds.Y);
            break;
        default:
            // für alle anderen SubItems
            // halbe Spaltenbreite der akt. Spalte ausrechnen
            int iWidth = ListView1.Columns[e.ColumnIndex].Width / 2;
            // halbe Zellenhöhe ausrechnen
            int iHeight = (int)(ListView1.Font.SizeInPoints / 2.0);
            // String mit akt. Subitem-Text zeichnen
            e.Graphics.DrawString(e.SubItem.Text, new Font("Microsoft Sans Serif", 8.25F, FontStyle.Regular), Brushes.Black, e.Bounds.X + iWidth, e.Bounds.Y + iHeight, sf);
            break;
    }
}

// ListView-Item Hintergrund speziell färben, wenn focusiert
private void ListView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
    if (e.State == ListViewItemStates.Focused)
    {
        e.Graphics.FillRectangle(Brushes.Beige, e.Bounds);
        e.DrawFocusRectangle();
    }
}