pátek 2. prosince 2011

WPF - Drag and Drop

Dnes jsem začal do WPF aplikace implementovat základní dovednost ve většině aplikací - Drag and Drop. Pojďme se podívat, jak Drag and Drop ve WPF funguje.

čtvrtek 1. prosince 2011

Každe okno aplikace ve vlastním vlákně - pokračování

Jak jsem zmínil nedávno v příspěvku, potřebuji do své poslední aplikace, aby každý modul a hlavně také jeho okno běžel v samostatném vlákně.

Požadavky:
- Když v jednom okně provádím náročnější operaci, nesmí vytuhnout ostatní okna.
- Když dojede k pádu v jednom modulu tak potřebuji, aby ostatní moduly fungovali dál.

Jak jsem psal v předešlém článku, požadovaného výsledku dosáhneme vytvořením STA vlákna pro každé okno.

Když pak spustíme aplikaci, zjistíme, že každé okno funguje opravdu v nezávislém vlákně. Brzo si všimnete velmi nepříjemné vlastnosti takové aplikace - okna jsou opravdu na sobě nezávislá a fungují jako samostatné aplikace uvnitř vaší aplikace. Důsledkem toho vám program přestane správně fungovat při minimalizaci a opětovné maximalizaci. Po opětovné maximalizaci se vám zobrazí pouze okno hlavního vlákna. Ale kde jsou ty ostatní okna?

První myšlenka, která mě napadla bylo, nastavení vlastnosti Window.Owner. Tuto vlastnost bohužel z jiného vlákna nenastavíte, protože tímto vyvoláte kód v hlavním vlákně.

_window.Owner = Application.Current.MainWindow;

Dojde k výjímce:
The calling thread cannot access this object because a different thread owns it.

Dlouho jsem procházel nejrůznější fóra, až jsem objevil konstrukci, která tuto WPF chybku obejde.

string strFriendlyName = AppDomain.CurrentDomain.FriendlyName;
Process[] pro = Process.GetProcessesByName(strFriendlyName.Substring(0, strFriendlyName.LastIndexOf('.')));            
typeof(System.Windows.Window).InvokeMember("_ownerHandle",
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetField,
null, _window, new object[] { pro[0].MainWindowHandle });
_window.Closed += new EventHandler(WindowClosed);
_window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
_window.ShowDialog();           

//System.Windows.Threading.Dispatcher.Run();

A můžeme si oddechnout, opravdu to funguje.

Odkaz na článek

pondělí 28. listopadu 2011

Složitost O(n)

Pokud softwarový designer navrhuje celý aplikační systém a vytváří vlastnosti tohoto systému jen z případu užití - Use cases, očekává od systému něco co navrhl. Dle mého názoru by si ale měl i designér, který není programátorem měl uvědomit, že jeho návrhy mohou významně ovlivnit většinu algoritmů v systému. Výsledkem čehož je pomalejší provádění všech algoritmů a větší čas potřebný ke zpracování. Vezměme si například geniální myšlenku využívání dynamických datových struktur namísto statických. A k tomu si přidejme navíc využívání multihodnot namísto jednohodnotových položek.

Poznámka:
Příkladem multihodnoty z běžného života je telefon. Mohu mít více telefonních čísel, proto se hodnota telefon v dynamické struktuře vyskytuje vícekrát.

Podívejme se na to, jak se změní v celém systému složitosti algorimu po zavedení dynamických datových struktur. Pro zjednodušení neuvažujeme že hodnotou u dynamické datové struktury může být jakýkoliv datový typ, vliv variantního typu a nutnosti přetypování je zanedbán.

A . Máme statickou datovou strukturu
LibraryElement
• elementID
• Artist[50]
• Title[50]

B. Máme dynamickou datovou strukturu
LibraryElement – je pole
Item[1] – elementID
Item[2] – Artist
Item[3] – Artist
.
.
.
Item[10] – Title
Zpracování jedno údaje ve struktuře má složitost O(1).
Zpracování jedné informace
Příklad 1. Abych zobrazil jednu položku např. Artist potřebuji složitost
M – počet atributů nebo chceteli počet položek ve struktůře
A. O(1)
B. O(2) – obecně O(M)

Zpracování pole informací – zpracování celé knihovny
Příklad 2. Zobrazení knihovny o N prvcích
A – počet zobrazovaných atributů
A. O(N*A)
B. O(N*A*M)
Příklad 3.Třídění informací – quicksort O(N log2 N)
A. O(N log2 N)
B. O((N*M) log2 (N *M))
Příklad 4. Přenos informací – složitost potřebná k serializaci a deserializaci

A. O(N) – u statické struktůry tedy mohu mluvit jednoduše o přenosu X KB/s
Vím, že chci úřenést (2b + 50+50) * N
B. O(N*M) - u statické struktury není správné mluvit o X KB/s … protože proces serializace a deserializace má mnohem větší složitost

WPF - Každé okno v aplikaci má vlastní vlákno - STA = Single threaded apartments, MTA = Multi-Threaded Apartments

Ve chvíli, kdy založíte nový projekt ve Visual Studio, vygeneruje se vám základní kostra aplikace. Která podle typu projektu WinForm nebo WPF vytvoří vstupní bod aplikace.

WinForm - funkce main
WPF - funkce main je skrytá, ale je možné ji přetížit a napsat si vlastní

Funkce main je vstupním bodem aplikace a je prováděna v hlavním vlákně aplikace (MainThread). Toto vlákno je nastaveno jako STA - Single thread apartments. Každé okno, které vytvoříme v aplikaci běží v rámci toho STA (kontejnéru na vlákna). Pokud budeme chtít vytvořit jiné vlákno, které bude provádět nějakou činnost, tak toto vlákno má nastaven apartments na MTA (multi-thread apartments). Data z tohoto vlákna můžeme synchronizovat do okna aplikace pomocí dispečeru.

myThread = new Thread(new ThreadStart(Execute));
myThread.Start();

V tomto vlákně máme nějaká omezení. Nemůžeme v něm vytvářet okna, ovládací prvky atd. Pokud chcete vytvořit nové okno v rámci jiného vlákna než je hlavní vlákno aplikace, vytvořte nové vlákno, ale nastavte mu apartments na STA.

myThread = new Thread(new ThreadStart(Execute));
myThread.Name = "Thread";
myThread.SetApartmentState(ApartmentState.STA);
myThread.IsBackground = true;
myThread.Start();

Nyní máme vytvořeno okno, ve kterém můžeme vytvořit nezávislé okno, ale aby okno fungovalo, musíme v rámci tohoto vlákna spustit dispečeram který se bude starat o případné synchronizace s jinými vlákny. Bez dispečera nebude okno fungovat.

oid Execute()
{
  MyWindow win = new MyWindow();
  win.Show();

  System.Windows.Threading.Dispatcher.Run();
}

Nezávislé okno máme hotovo.

Závěr
Hledal jsem příčinu, proč jsou takto pod .NETem vlákna řešena. Toto řešení se mi zdálo zbytečně komplikované. Ve většině článků bylo odůvodnění, že je to z důvodů zpětné kompatibility s COM objekty. Do hlubšího zkoumání jsem se už nepouštěl!

čtvrtek 24. listopadu 2011

1. Paralerní programování - Datový paralelismus

V .NET frameworku 4 můžeme využívat tzv. datový paralelismus. Pokud máme v aplikaci nějaký sekvenční algoritmus, který například prochází nějaké velké pole (vřádu desítek tisíc položek), tak může operace trvat dlouho, což může mít za následek výtuhnutí (zaneprázdnění) hlavního vlákna.

1. Příklad - Potřebujeme setřídit data, ale třídíme velké množství položek - sekvenčně pomocí LINQ

public void Sort()
{            
 _log.Debug("Begin Sort!"); 
 var elements = (from val in this select val).OrderBy(a => a, _comparer);
 List<LibraryElement> sort_list = elements.ToList();
 base.Clear();
 base.AddRange(sort_list); 
 _log.Debug("End Sort!"); 
}

Stejný příklad pomocí datového paralelizmu
2. Příklad - Potřebujeme setřídit data - paralelně pomocí PLINQ

public void Sort()
{            
 _log.Debug("Begin Sort!"); 
 var elements = (from val in this.AsParallel() select val).OrderBy(a => a, _comparer);
 List<LibraryElement> sort_list = elements.ToList();
 base.Clear();
 base.AddRange(sort_list); 
 _log.Debug("End Sort!"); 
}

Data jsme setřídili mnohem rychleji, protože TPL nabízí jednoduchý způsob, jak v aplikaci umožnit paralelní zpracování – tedy co nejefektivnější zpracování dat s využitím všech dostupných jader procesoru.

středa 23. listopadu 2011

Paralelní programování v .NET

Knihovna TPL je rozhraní API ze jmenných prostorů System.Threding, System.Threading.Tasks v .net frameworku 4. Knihovna umožňuje paralelně zpracovávat úlohy (tasks), která úkoly rozkládá dyamicky na všechny procesory. Použití TPL rozloží požadovaný úkol na části, které naplánuje do vláken a spouští s využitím fondu vláken ThreadPool (design pattern). Při provádění úlohy máme požnost sledovat stav provádění nebo úlohu přerušit.

Knihovna TPL se dělí:
Datový paralelizmus
Úkolový paralelizmus
PLINQ

SyntaxColor Highlighter

Konečně jsem si sehnal obarvovač zdrojového kódu, abych zde mohl uveřejňovat zdrojové kódy.
Inspiroval jsem se na stránkách:
http://xtractpro.com/tools/CSharp-Highlighter.aspx


Test:


    
    
    public partial class App : Application
    {
        

        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            ModulesManager bootstrapper = new ModulesManager();            
            bootstrapper.Run();
            bootstrapper.PostCreate();            
        }

        public void ApplyLocalSkin(Uri skinDictionaryUri)
        {
            
            ResourceDictionary skinDict = Application.LoadComponent(skinDictionaryUri) as ResourceDictionary;

            Collection<ResourceDictionary> mergedDicts = base.Resources.MergedDictionaries;
            
            
            
            
            if (mergedDicts.Count > 0)
                mergedDicts.Clear();

            
            
            mergedDicts.Add(skinDict);
        }

        public void ApplyFileSkin(string file)
        {
            using (FileStream fs = new FileStream(file, FileMode.Open))
            {
                ResourceDictionary dic = (ResourceDictionary)XamlReader.Load(fs);
                Resources.MergedDictionaries.Clear();
                Resources.MergedDictionaries.Add(dic);
            }
        }

    }

pondělí 3. října 2011

O víkendu jsem dočetl knihu - Návrhové vzory od Rudolfa Pecinovského

Návrhové vzory od Rudolfa Pecinovského
návrhové vzory = design patterns

Návrhové vzory umožňují zvýšit efektivitu při vývoji, umožňují psát znovupoužitelný kód, umožnuje psát znovupoužitelný kód a nabízí řešení obvyklích programátorských problémů.

pondělí 19. září 2011

Unity vs MEF vs PRISM


Unity, MEF a PRISM jsou kniovny, které řeší závyslosti, modularitu a lehkou rozšiřitelnost vaší aplikace. Podívejme se stručně, jaké jsou v nich rozdíly.


Unity vs MEF
Unity se nejvíce používá k pro pevné statické závislosti a je to více "vnitřní" technologie. Nikdo mimo vyvojáře nic nemusí vědět o vnitřním uspořádaní aplikace.
MEF se používá pro řešení dynamických závislostí, dynamické načítání komponent. Pomocí MEF lze snadno tvořit rozšiřující moduly aplikace.


PRISM 
Je framework využívající Unity nebo MEF, který umožňuje vytvářet modulární aplikace, kdy si aplikace může sama moduly natahovat až ve chvíly kdy je potřebuje. Pomocí RegionManager můžete pohledy z modulů vkládat do hlavního okna (Shell) aplikace. Pro sdílení událostí se využívá EventAggregator a Command. PRISM je možné využít s výhodou u návrhového vzoru ModelView-ViewModel.

Pod čarou:
  • MEFnení IoC (Inversion of Control) kontejnér, ale využívá IoC koncept.
  • Unity je IoC kontejnér.
  • MEF se zaměřuje především na rozšiřitelnost aplikace a na uspořádání pomocí kompozice. Aplikaci skládáme z částí.
  • PRISM je kompletní řešení pro tvorbu uživatelských aplikací.
  • MEF není kompletní řešení pro tvorbu uživatelských aplikací, je to jen knihovna umožňující snadnou rozšiřitelnost aplikace.

pondělí 12. září 2011

DI - depency injection - Unity

Materiál:

http://www.codeproject.com/KB/cs/MEF_UnityInterception.aspx
http://martinfowler.com/articles/injection.html
- Skrýt citovaný text -


2011/9/12 Michal Svoboda
http://weblogs.asp.net/podwysocki/archive/2008/02/26/ioc-and-the-unity-application-block-once-again.aspx
http://entlib.codeplex.com/
http://msdn.microsoft.com/en-us/magazine/cc163739.aspx#S8

Mixed DLL - Kombinované DLL - (.net a nativní)

Před 14 dny jsem dostal úkol, volat funkce a DLL mého kolegy. DLL je napsané v C++ Builderu tedy v nativním běhovém prostředí. Spouštění funkcí z nativního DLL není nic světoborného a .NET na to má sekci zvanou System.Runtime.InteropServices. Rozhodl jsem se napsat tuto glosu, protože občas se mi DLL zavolá v pořádku a občas volání selže. Hledal jsem nejrůznější články na googlu a narazil jsem pouze na tzv. Mixed DLL problém:
http://www.codeguru.com/columns/kate/article.php/c3643

Na MSDN je celý článek o volání native DLL:
http://msdn.microsoft.com/en-us/magazine/cc164123.aspx

Důležitým parametrem pro volání je volací konvence CallingConvention = CallingConvention.Cdecl. Máte na výběr z několika volacích konvencí: Cdecl, StdCall, FastCall, ThisCall a WinApi

Při volání funkcí předáváme parametry a musíme zajistit, aby parametry z .net odpovídali parametrům z nativního světa.

char = System.SByte
int = System.Int32

O předávání dat se stará tzv. Marshaling
Můžeme využít defaultního předávání dat, ale pokud z nějakého důvodu .net typ neodpovídá nativnímu typu mužeme si explicitně říct, jakým způsobem chceme data u konkrétního parametru předat. K tomu slouží: [MarshalAs(UnmanagedType.LPWStr)]jméno_parametru. Toto využijeme zvláště při například u stringů nebo složitějších polí.

Pokud v .net pracujeme se stringem, definujeme jej jako string. V C/C++ je situace poněkud složitější. Můžeme pracovat s C stringem, to je pole znaků char, pak můžeme mít pole unicode znaků wchar_t nebo bstr stringy a podobně. Proto při předávání .NETu musíme explicitně říct, jaký string chceme do nativního prostředí předat.

Příklad: BStr, LPStr, LPWStr,  LPTStr atd.

Příklad volání:
[DllImport("ImportGS.dll", EntryPoint = "_DB_ImportXML", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern int db_ImportXML(string filename, TFileType type, bool full);

Importovanou funkci si můžete pojmenovat libovolným způsobem, ale pak musíte její jméno napsat do Attributu EntryPoint a také musíte dát pozor na volací konvence a '_'. Dáe musíte dát pozor na typy řetězců.

Nyní již umíme zavolat nativní dll, ale podívejme se ješte jak může takové dll zavolat náš .net kód zpět pomocí callbacku.

Callback
V hlavičkovém souboru jsem měl definovaný callback:
typedef void (TNotice)(wchar_t *msg, bool error);
V Céčku je callback reprezentovaný jako ukazatel nafunkci. V .NETu takový callback realizujeme pomocí delegáta:

 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
 public delegate void CallbackDelegate([MarshalAs(UnmanagedType.LPWStr)]StringBuilder msg, bool error);

Explicitně říkám, že jde o UnmanagedFunctionPointer (ukazatel z jiného světa :)) a určím jeho volací konvenci. Pak definuju delegáta tak, aby mu odpovídali parametry s jeho Céčkovským protějškem. A také určím, jak se mají předávat parametry Marshalingem.

Na závěr bych chtěl ještě upozornit na možnost předávat a zpracovávat parametry více způsoby. Vezměme si oblíbený string.

String je možné předávat jako string, StringBuilder a nebo například jako IntPtr, který si přetypujeme až v těle delegáta.

StringBuilder využíváme v případě, že se řetězec předává jako reference a vrátí se mi zpět změněný.

Pokud si předáme string jako IntPtr msg, tak výsledný string získáme voláním:
string msg_decode = System.Runtime.InteropServices.Marshal.PtrToStringUni(msg);


pátek 29. července 2011

Reflexe - dynamické volání metod

Dnes jsem se dostal před problém, dynamicky volat funkce v nějaké třídě. Někde budu mít uloženo jméno funkce a seznam parametrů s hodnotamy a já takto zavolám funkci. V .NETu to není samozřejmě problém díky vlastnosti zvané reflexe.

Uvádím jednoduchý příklad, pomocí kterého zavoláte funkci jejím jménem:


        public static string InvokeStringMethod(string typeName, string methodName)
        {
            // Get the Type for the class
            Type calledType = Type.GetType(typeName);

            // Invoke the method itself. The string returned by the method winds up in s
            String s = (String)calledType.InvokeMember(
            methodName,
            BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static,
            null,
            null,
            null);

            // Return the string that was returned by the called method.
            return s;
        }

středa 27. července 2011

WCF Přenos velkých dat (Large objects), problémy s přenosem složitějších objektů

1. Při serializaci a deserializaci objektů, které přenášíte přes WCF  se vám může vyskytnout vyjjímka:
"System.Runtime.Serialization.SerializationException : Maximum number of items that can be serialized or deserialized in an object graph is '65536'. Change the object graph or increase the MaxItemsInObjectGraph quota.". To znamená, že přenášíte příliš velké množství položek a musíte upravit konfiguraci  chování koncového bodu tak, aby mylo možné přenášet velké množství položek. 

Příklad: 







2. Přestože jsem měl nastavený přenos velkého množství položek, někdy se mi přenos pomocí WCF  zasekával. Pátral jsem po tom problému a zjistil jsem, že WCF serializér umí přenášet jen data, které jsou serialozovatelné (Serializable).

MessageQueing - MSMQ

WCF Notifikace

WCF Transakce

Info:
http://msdn.microsoft.com/en-us/magazine/cc163688.aspx#S3


V každé literatuře o .NET se dočtete o podpoře transakcí uvniřt .NETu. A všechny příklady zabívající se touto problematikou jsou ukazovány na databázích. Nebudu zde popisovat jednotlivé programovací konstrukce, kterých se na netu v příkladech vyskytuje hodně. Zmíním jen konstrukci tzv. ambientní transakce, což je blok, uvnitř kterého probíhá automaticky transakce. Tato transakce se sama zahájí a na konci voláním metody Complete() se potvrdí.


using (TransactionScope sc = new TransactionScope)
{
sc.Complete();
}


Ale nyní přichází požadavek. Potřeboval bych naprogramovat pole objektů, které spravuji v paměti a potřebuji aby nad tímto polem fungovalo transakční zpracování. Je to možné? Funguje to? 
Odpověď zní ANO i NE.


Samozřejmě je o možné naprogramovat, ale nefunguje to automaticky. Nelze deklarovat před blokem proměnou, pak uvnitř bloku nastavit nějakou hodnotu této proměnné. Nakonec transakci nepotvrdit. Hodnota se nevrátí do původního stavu.


Proč?
Transakce můžeme využívat pouze transakčním zdrojem dat, nad transakčním modelem. Takovým transakčním zdrojem je například nějaké databázové připojení - SqlConnection. Pokud chceme transakce využívat pro jednoduché datové typy nebo objekty, musíme pro ně naprogramovat transakční zdroj. Na internetu lze stáhnout již naprogramované transakční zdroje:





Developer blog

... od nynějška zde budu psát své vývojářské postřehy

středa 9. února 2011

Co se u mně děje v číslech

2+1 v 3+1; 50mm; 30 let

Už je únor ...

Už je únor a já v novém roce nenapsal ani řádku do blogu. Těžce se mi píše, protože se mi rozpíjí inkoust na stářím zašlém html blogovém papíře. Tak alespoň sfouknu prach .... ah, už je to dobré