Monthly Archives: June 2006

Creating your own settings provider – example

Sometimes you’ll need to create settings provider, which allows you to save configuration into specific format and/or specific place. In FW are some basic providers, but creating your own isn’t difficult.< ?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

This example shows (easy) way how to build simple provider, which save data into the specified file in xml.

Note: Our provider will save only user scope settings (the default behavior of standard providers) but it’s not necessary.

So, create new class and implement abstract class SettingsProvider. The first method we’ll care about is public override void Initialize(string name, NameValueCollection config). For this method we’ll provide only calling the parent.



public override void Initialize(string name, NameValueCollection config)

{

base.Initialize(this.ApplicationName, config);

}



Next method/property is public override string ApplicationName. With it you can handle (as you probably feel) application name. We’ll provide very simple implementation.



public override string ApplicationName

{

get { return Application.ProductName; }

set { }

}



Next method is public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection). This method is called when “reading the configuration”. So here we have to implement reading file (or any other storage) and filling the SettingsPropertyValueCollection collection. The first step is preparing the structure:


SettingsPropertyValueCollection values = new SettingsPropertyValueCollection();

foreach (SettingsProperty property in collection)

{

SettingsPropertyValue value = new SettingsPropertyValue(property);

value.IsDirty = false;

values.Add(value);
}



Then we’ll check whether or not the (method for getting path will be discussed later) file exists:



if (!File.Exists(this.GetSavingPath))

return values;



And next we try to read our XML file with configuration and after returning result:

using (XmlTextReader tr = new XmlTextReader(this.GetSavingPath))

{

try

{

tr.ReadStartElement(“ID3renamer”);

foreach (SettingsPropertyValue value in values)

{

if (IsUserScoped(value.Property))

{

try

{

tr.ReadStartElement(value.Name);

value.SerializedValue = tr.ReadContentAsObject();

tr.ReadEndElement();

}

catch (XmlException)

{ /* ugly */ }

}

}

tr.ReadEndElement();

}

catch (XmlException)

{ /* ugly */ }

}

return values;



OK, the method for „reading“ is done. Continuing with „saving“. The method is public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection) and it’s very similar to reading (in fact does the same in “reverse” order).



using (XmlTextWriter tw = new XmlTextWriter(this.GetSavingPath, Encoding.Unicode))

{

tw.WriteStartDocument();

tw.WriteStartElement(“ID3renamer”);

foreach (SettingsPropertyValue propertyValue in collection)

{

if (IsUserScoped(propertyValue.Property))

{

tw.WriteStartElement(propertyValue.Name);

tw.WriteValue(propertyValue.SerializedValue);

tw.WriteEndElement();

}

}

tw.WriteEndElement();

tw.WriteEndDocument();

}



And that’s it. This is very simple sample provider. You can build your own for your specific needs without problem.

I’m using some helper methods. I hope there’s no need to comment it, so I’ll provide it „as-is“.



private bool IsUserScoped(SettingsProperty property)

{

return property.Attributes.ContainsKey(typeof(UserScopedSettingAttribute));

}



private string GetSavingPath

{

get

{

return Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + Path.DirectorySeparatorChar + “ID3 renamer” + Path.DirectorySeparatorChar + “user.config”;

}

}



Note: This is part of my own provider (to understand some ‘ID3 renamer’ strings) used in my ID3 renamer application (which is now in „to .NET rewriting“ phase). :-)

Looking for user application data path

Today I was looking for user application data path (Application.UserAppDataPath) but without creating the Base PathCompanyNameProductNameProductVersion structure. I was really confused with this, but suddenly I found the solution. (ok, you’re right, I should use google prior to surfing in documentation :) ) The Environment.SpecialFolder enumeration and Environment.GetFolderPath – it’s so easy.

So the result is:
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)

or maybe better for you:
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)+Path.DirectorySeparatorChar

.NET Framework 3.0???

Tak se nám v posledních pár dnech rozpoutaly pěkné diskuze o WinFX vs. .NET Framework 3.0 (pokud nevíte oč kráčí navštivte http://blogs.msdn.com/somasegar/archive/2006/06/09/624300.aspx a další na msdn).

Nechci rozebírat jestli je to dobře a nebo jestli se mi WinFX více líbí (přejmenování se celkem dalo čekat nebo spíše se dá přijmout). Spíše by mě zajímalo, co si myslíte o kroku overzovat FW číslem 3. CLR bude pořád 2.0, jen se přidají další featurky, základ však zůstane stejný. Nemělo by se spíš změnit minor číslo?
Už vidím ten bordel v instalacích, potřebách aplikací, neshodách při pokládání dotazů do diskuzí, …

A jaký názor máte vy?

Navigace v kódu

Jak již (myslím) někdo tady psal (chtěl jsem najít link, ale nepovedlo se, už je někde moc vzadu) tak poměrně silně zabržduje Visual Studio ta lišta s ComboBoxem, kde jsou vidět metody a je možné na ně jednoduše “skočit”. Protože dělám hodně na notebooku, který není nejnovější, je každé procento výkonu znát a tak jsem tuto věcičku podle odkazovaného návodu vypnul. Rychlost pohybu kurzoru v kódu opravdu citelně vzrostla, ale měl jsem divný pocit, že nemůže nějak rychle skákat v kódu a tak jsem hledal něco co by toto nahradilo (zapínání a vypínání té lišty se mi nezdálo dobré). V Delphi existovat expert (z GExperts) který umožnovat inkrementálně vyhledat v seznamu metod a pak se event. na ni přesunout. Hledal jsem něco podobného, ale marně (a další add-iny se mi instalovat nechce).
Našel jsem ale inkrementální hledání (nevím jak moc jej používáte) pod Ctrl[+Shift]+I (std. v C#) a chvíli jsem si zvykal (dríve jsem jej používal jen občas). Nyní ale dokážu díky tomuto velmi rychle v kódu skákat kam zrovna potřebuju (a když si vybavíte něco co je v té metodě jedinečné, jde to rychle).
Rozhodně mi lišta nyní nechybí a díky Ctrl+I můžu hledat nejen podle názvu metod. Pokud na první pokus najdete něco co nechcete a chcete se přesunout na další výsledek, překvapivě to neuděláte šipkou (jak jsem byl zvyklý já), ale opětovným stisknutím Ctrl[+Shift]+I (šipka mi připadá přirozenější a Esc na ukončení). Určitě je to někde napsané, ale kdo by to hledal, když to můzů objevit empiricky, že? :-)

Jak “poskakujete” v kódu vy? Máte své fígly?

SynchronizationContext class – how to use it?

In .NET framework 2.0 is new class SynchronizationContext. This class can be very helpful when using threads and communication (and collaboration) between threads.

Before, if you want to i.e. do something with some control on form (or just do something in another thread) you have to use the Invoke method of the object (most common of form) and use the InvokeRequired property to determine how and what to do. This means, that the receiver must care about this stuff about threads. With the new SynchronizationContext class this logic is back in the sender.
Look at this code:

public partial class Form1 : Form< ?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

{

public Form1()

{

InitializeComponent();

}

private void button1_Click(object sender, EventArgs e)

{

new Thread(new ThreadStart(new UsefulClass(this).DoWork)).Start();

}

public void AnotherDoWork(string text)

{

button1.Text = text;

}

}

class UsefulClass

{

private Form1 _form;

private SynchronizationContext _context;

public UsefulClass(Form1 form)

{

_form = form;

}

public void DoWork()

{

Thread.Sleep(2000);

_form.AnotherDoWork(“jirka”);

Thread.Sleep(2000);

}

}

If you try to run it you will get InvalidOperationException exception saying that cross-thread operation is not valid. To solve this you have to modify the code using Invoke/BeginInvoke and InvokeRequired, as you know.

Now look at the example with SynchronizationContext class:

class UsefulClass

{

private Form1 _form;

private SynchronizationContext _context;

public UsefulClass(Form1 form)

{

_form = form;

_context = SynchronizationContext.Current;

if (_context == null)

{

_context = new SynchronizationContext();

}

}

public void DoWork()

{

Thread.Sleep(2000);

_context.Post(

new SendOrPostCallback(delegate { _form.AnotherDoWork(“jirka”); }),

null);

Thread.Sleep(2000);

}

}

In the contructor of the class we get the SynchronizationContext from the Current property and if there’s null we simply create a new one (this test is important, there’s no need to exist the object in Current property). As you can see we’re using the SynchronizationContext’s method Post to “invoke” the method in right way. And that’s all. There’s also Send method for synchronous operation.

I hope this (really) easy example will help you with playing and understanding this class and threads.
Any comments welcome.