venerdì 27 gennaio 2012

String format .NET semplificato e naturale

Molte volte ci troviamo a dover inserire delle stringhe in una stringa più grande (di solito una frase, per notificare un messaggio all’utente dell’applicazione).
Per fare ciò usiamo il metodo “String.Format()” che accetta in input la stringa da formattare, e un array contenete le altre stringhe da inserire, al posto di segna posti speciali, costruiti con la regola: {indice dell’array}.
Es.:
MessageBox.Show(String.Format("Errore numero {0}, l'utente {1}, non ha i permessi di lettura del file
 {2}, inoltre {1}, non appartiene al ruolo {3}", new String[]{"123", "Mario", "file.txt", "admin"}));
Di solito la scrittura di questo codice avviene nella seguente maniera:
  1. Si scrive: MessageBox.Show(
  2. Si pensa al messaggio e si inizia a scriverlo: "Errore numero …
  3. Ci si accorge che il messaggio dovrà contenere dei pezzi di stringa all’interno della stringa principale.
  4. Si aggiungono i segna posto per i pezzi di stringa: numero {0}, l'utente {1}, non
  5. Completata la frase, ci si posiziona all’inizio della frase stessa.
  6. Si digita String.Format(
  7. Si va alla fine della frase e si chiude la parentesi )
Come si vede a lungo andare si perde molto tempo a compiere tale operazione e non è del tutto naturale, perché ci impegna a cercare l’inizio della frase scritta per aggiungere un pezzo di codice e a tornare alla fine di essa, per chiudere la parentesi.
Per risparmiare tempo e trovare più naturalezza nella scrittura, ho implementato la seguente classe per estendere la classe System.String:
namespace System
{
    /// <summary>
    /// Estensioni per le classi stringa
    /// </summary>
    public static class StringEx
    {
        /// <summary>
        /// Formatta la stringa
        /// </summary>
        /// <param name="pValue">Stringa</param>
        /// <param name="args">Parametri</param>
        /// <returns>Stringa formattata</returns>
        public static string Formatting(this String pValue, params object[] args)
        {
            return String.Format(pValue, args);
        }

        /// <summary>
        /// Formatta la stringa
        /// </summary>
        /// <param name="pValue">Stringa</param>
        /// <param name="format">Format provider</param>
        /// <param name="args">Parametri</param>
        /// <returns>Stringa formattata</returns>
        public static string Formatting(this String pValue, IFormatProvider format, params object[] args)
        {
            return String.Format(format, pValue, args);
        }
    }
}
Ora potere scrivere lo stesso codice dell’esempio di prima in maniera naturale, senza bisogno di tornare a cercare dove inizia la vostra Stringa:
MessageBox.Show("Errore numero {0}, l'utente {1}, non ha i permessi di lettura del file {2}, inoltre {1},
 non appartiene al ruolo {3}".Formatting(new String[] { "123", "Mario", "file.txt", "admin" }));

sabato 14 gennaio 2012

Implementare il Databindings di oggetti

Oggi mi è capitato di dover implementare il databindings di un controllo che ne era sprovvisto (il treenode). Per aggiungere il databindings ad un oggetto TreeNode, come nel mio caso, ma anche per qualsiasi altro oggetto, basta implementare l’interfaccia IBindableComponent.

In questo modo potete usare il Binding su tutte le proprietà del TreeNode; in particolare a me interessava collegare la proprietà “Name” di un mio oggetto alla proprietà “Text” di un TreeNode.

Ecco un esempio in C# dell’implementazione del databindings per la proprietà “Text” di un oggetto TreeNode:
public class TreeNodeBind : TreeNode, IBindableComponent
    {
        //Implementazione dei costruttori base
        public TreeNodeBind()
            : base()
        {
        }

        public TreeNodeBind(string text) 
            : base(text)
        {
        }

        public TreeNodeBind(string text, TreeNode[] children)
            : base(text, children)
        {
        }

        public TreeNodeBind(string text, int imgIndex, int selImgIndex) 
            : base(text, imgIndex, selImgIndex)
        {
        }

        public TreeNodeBind(string text, int imgIndex, int selImgIndex, TreeNode[] children)
            : base(text, imgIndex, selImgIndex, children)
        {
        }

        //Implementazione di IBindableComponent
        #region IBindableComponent Members

        private BindingContext _bindingContext;
        private ControlBindingsCollection _dataBindings;

        [Browsable(false)]
        public BindingContext BindingContext
        {
            get
            {
                if (_bindingContext == null)
                {
                    _bindingContext = new BindingContext();
                }
                return _bindingContext;
            }
            set
            {
                _bindingContext = value;
            }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public ControlBindingsCollection DataBindings
        {
            get { return _dataBindings ?? (_dataBindings = new ControlBindingsCollection(this)); }
        }

        public ISite Site { get; set; }

        public event EventHandler Disposed;

        public void Dispose()
        {
            if (Disposed != null)
                Disposed(this, EventArgs.Empty);
        }

        #endregion
    }
Ora potete creare ed usare nodi di tipo TreeNodeBind che supportano il Binding:
TreeNodeBind nodoBind = new TreeNodeBind();
nodoBind.DataBindings.Add(new System.Windows.Forms.Binding("Text", oggettoConDati, "Name", true));
tree.Nodes.Add(nodoBind);