středa 7. května 2014

WPF - Jak změnit vzhled Focus rámečku?

Každému se tečkovaný Focus rámeček nemusí líbit. U ovládacího prvku stačí nastavit:
FocusVisualStyle="{StaticResource MyFocusVisualStyle}"

 A příklad:
<SolidColorBrush x:Key="SelectBrushAlpha" Color="#99288AF7"/>    
    <Style x:Key="MyFocusVisualStyle">
        <Setter Property="Control.Template">
            <Setter.Value>
                <ControlTemplate>
                    <Rectangle Fill="{StaticResource SelectBrushAlpha}" SnapsToDevicePixels="true" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

WPF - KeyboardNavigation - Navigace pomocí kláves v ItemsControl nebo v jiném 'kontejnéru'

Jako uživatel windows aplikací se řadím spíše mezi takzvané klikače, proto mi velice často unikají ve vývoji potřeby příznivců tzv. klávesovačů - čili uživatelů vyplňujících okna pomocí klávesnice a klávesových zkratek. Takže tyto detajly musím dolaďovat jako vývojář v závěrečné fázi před nasazením.




Pokud si okno skládáte ručně, tak si zpravidla vystačíte s nastavováním TabIndexů, které určí pořadí editace při stisknutí klávesy Tab. Jelikož mám editor postavený dynamicky přes ItemsControl, tak jsem TabIndex nevyužil. Klávesou Tab naviguji z jedné položky ItemsControl na druhou.

Celkem zajímavá je ale možnost ale ovlivnit možnost navigace klávesnící ItemsControl, připadně v jiném kontejnéru.

Navigaci klávesnící ovlivním snadno přes třídu - KeyboardNavigation.
V MSDN si o tom můžete přečíst ZDE.

Navigaci přes Tabulátor ovlivníte  - KeyboardNavigation.TabNavigation
Směrovou navigaci přes šipky ovlivníte  - KeyboardNavigation.DirectionalNavigation

A možnosti jsou následující: Contained, Continue, Cycle, Local, None, Once

Nejlépe je si chování vyzkoušet na příkladu:

<GroupBox Header="Check Boxes" KeyboardNavigation.TabNavigation="Once"
                  Height="126" HorizontalAlignment="Left" 
                  VerticalAlignment="Top" Width="200">
            <StackPanel Margin="8">
                <CheckBox Content="Check Box 1"/>
                <CheckBox Content="Check Box 2"/>
                <CheckBox Content="Check Box 3"/>
                <CheckBox Content="Check Box 4"/>
                <CheckBox Content="Check Box 5"/>
            </StackPanel>
        </GroupBox>
        
        <GroupBox x:Name="gbRadio" Header="Radio Buttons" Height="126" VerticalAlignment="Top" Margin="206,0,107,0">
            <StackPanel Margin="8">
                <RadioButton x:Name="radio1" Content="Radio Button 1"/>
                <RadioButton Content="Radio Button 2"/>
                <RadioButton Content="Radio Button 3"/>
                <RadioButton Content="Radio Button 4"/>
                <RadioButton Content="Radio Button 5"/>
            </StackPanel>
        </GroupBox>

A přitom taková blbost, ale potěší :).

pondělí 17. března 2014

Můj první CmdLet do Powershellu.

Můj první CmdLet do Powershellu

Po jedné diskuzi s kamarádem, který pracuje v Praze jako serverový správce na platformě windows, jsem dospěl k názoru, že Powershell může býti užitečný nástroj.  Protože jsem kluk zvědaví, rozhodl jsem se, že přehodnotím předsudek, který vůči powershellu mám - skriptovací sračka ala vbscript, jscript.

K čemu by mohlo být spouštění takového skriptu dobré v našich rádiových podmínkách? Položil jsem si otázku. Máme server, na kterém běží pán démonů. Tento pán démonů nám spouští joby, když přijde nějaká událost (podnět) - časová událost, změní se soubor, nebo přijde podnět přes HTTP. Joby máme zapsané jako posloupnost akcí, definovaných v nějakém popisném XML souboru.

Co kdyby pán démonů místo našich jobů spouštěl powershell scripty?
Co kdybych začal jednoduše tím, že si napíši svůj první CmdLet.

1. Vytvořím si C# project ClassLibary a přidám si referenci na System.Management.Automation.dll assembly, která obsahuje třídy PSCmdlet a PSSnapIn.

Třída PSSnapIn slouží k registraci přídavného balíčku PSSnapIn. Její význam jsem úplně nepochopil. Možná, aby mohlo být vše složitější.

[RunInstaller(true)]
    public class CmdLetSnapIn : PSSnapIn
    {
        public override string Name
        {
            get { return "CmdLet"; }
        }
        public override string Vendor
        {
            get { return ""; }
        }
        public override string VendorResource
        {
            get { return "CmdLet,"; }
        }
        public override string Description
        {
            get { return "Registers the CmdLets and Providers in this assembly"; }
        }
        public override string DescriptionResource
        {
            get { return "CmdLet,Registers the CmdLets and Providers in this assembly"; }
        }
    }

Třída PSCmdlet, je třída CmdLetu. Třída slouží k vykonání CmdLetu.
[Cmdlet(VerbsCommon.Get, "CmdTest", SupportsShouldProcess = true)]
    public class CmdTest : PSCmdlet
    {

        #region Parameters
        /*
        [Parameter(Position = 0,
            Mandatory = false,
            ValueFromPipelineByPropertyName = true,
            HelpMessage = "Help Text")]
        [ValidateNotNullOrEmpty]
        public string Name
        {
            
        }
        */
        #endregion

        protected override void ProcessRecord()
        {
            try
            {
                WriteObject(System.Diagnostics.Process.GetProcesses(), true);
            }
            catch (Exception)
            {
            }
        }
    }

Třída má definovaný důležitý attribut Cmdlet, kterým říkáme, jakým slovesem jej budeme volat - VerbsCommon.Get, dalším parametrem attributu je jméno command letu - CmdTest. Takovýto command let zavoláme z powershell konzole jako Get-CmdTest . Tato třída CmdTest má povinnou funkci ProcessRecord(), která je vykonávací funkcí CommandLetu. Pro zápis do výstupu voláme WriteObject. Tento command let neobsahuje žádné parametry, ale mohli bychom si parametry definovat velice jednoduchým způsobem: pomocí property atributu Parameter - [Parameter(Position = 0, Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "Help Text")].

To je tak k prvnímu CmdLetu asi vše. Nyní jej můžeme zkompilovat a nainstalovat. Nahrajeme jej do cesty s Moduly - cesta je uložená v systémové proměné PSModulePath. Pak už můžeme vesele spustit konzoli Powershellu.


  • SnapIn registrujeme pomocí .NET utiliti InstallUtil jmenosnapinu (cesta dll)
  • Registrované přílepky si vylistujeme: Get-PSSnapIn -registered - tady se objeví v seznamu CmdLet (jméno z třídy PSSnapIn).
  • SnapIn přidámě pomocí Add-PSSnapIn CmdLet
  • CmdLet zavoláme pomocí Get-CmdTest (!!!Název definovaný attributem Cmdlet!!!)



pondělí 13. ledna 2014

.NET Memory leaks

Problém: Zdravím, máme celkem rozsáhlý projekt v .NET, který také volá nativní dll. Aplikaci neustále narůstá paměť.

úterý 31. prosince 2013

Nový rok 2014

Všechno nejlepší do Nového roku 2014, hodně čistého a znovupoužitého kódu, který přežije nejeden projekt.

A hlavně zdravíčko a dobré přátele.

středa 4. prosince 2013

Immutable collections in .NET



http://blogs.msdn.com/b/dotnet/archive/2013/09/25/immutable-collections-ready-for-prime-time.aspx
http://msdn.microsoft.com/en-us/library/dn467185(v=vs.110).aspx
http://blogs.msdn.com/b/ericlippert/archive/2007/11/13/immutability-in-c-part-one-kinds-of-immutability.aspx

Spojování dvou a více .NET Assembly.

Pokud programujete v C nebo C++, tak jistě víte, že knihovny lze linkovat do výsledné aplikace staticky nebo dynamicky. Pokud linkujete staticky, tak se vám knihovny připojí k výsledné aplikaci a nepotřebujete nic dalšího k aplikaci přidávat. Pokud linkujete dynamicky musíte mít společně s aplikací také dynamické knihovny dll.

V prostředí .NET ale jsou knihovny referencované dynamicky a s aplikací teda potřebujete i .NET dll knihovny.

Tak mě napadlo, jestli by nešlo .NET assembly slinkovat také staticky. Vše nasvědčuje tomu, že žádné statické slinkování nenní možné jak jsme byli zvyklí z céčka.
Googloval jsem na netu a řešením je spojení více assembly do jedné použitím utility ILMerge.exe

ILMerge

čtvrtek 28. listopadu 2013

GIT - aplikace patche

Na správu mého GIT repozitáře, použivam SourceTree od Atlassianu. Aktuální verze 1.3.2 neumí vytvářet patche do souboru a následně je aplikovat v jiné větvi. Přes git konzoli to alr není žádný problém.

$ git format-patch BruceLee --stdout > z:/lib.patch

Git vytvořil z podsledního komitu větve BruceLee rozdílový soubor a uložil ho do z:/lib.patch.

Nyní se můžete přepnout do větve, kde chcete patch aplikovat.
Aplikaci patche můžete otestovat.

$git apply --check z:/lib.patch

A pokud je vše v pořádku, můžeme patch aplikovat.

git am --signoff < z:/lib.patch

čtvrtek 7. listopadu 2013

What is SignalR?

http://signalr.net/

ASP .NET MVC - hostování webové aplikace v konzolové aplikaci

Pojďme se podívat zase na jeden problém z vývojářského života. Máme svůj vlastní klient - server systém a server nám běží jako služba ve windows nebo jako konzolová aplikace. Jedná se o náš vlastní server. Tento server má přístup do SQL a data zpřístupňuje pro klienty pomocí webových služeb. Protože dotazy na některá data jsou časově náročné, server si udržuje vlastní cache.

Já bych potřeboval do tohoto serveru přidat další modul (dll), který se při startu zavede pomocí MEF. Já bych potřeboval, aby tento modul poskytoval webovou aplikaci ASP .NET MVC - Razor. Myslel jsem si, že to nebude vůbec žádný problém, protože já již umím hostovat MVC Web API. K tomu se používá třída
HttpSelfHostServer
Tutorial o ASP .NET Self hosting WebAPI

Hostování Web API mám vyzkoušené a funguje bez problému, tak jsem zkoušel také nahostovat webovou aplikaci která hostuje MVC stránky s enginem Razor.

Řešení jsem prozatím nenašel, berte to špíše jako položenou otázku a sběr informací.

Jedna možnost je použití knihovny RazorEngine. Pokud se chcete vyhnout neoficiálním knihovnám třetích stran, pojďme ještě hledat dál.

Dále je možné hostovat webovou aplikaci pomocí

IIS 7.0 Hostable Web Core

pondělí 21. října 2013

C# JSON Serializace a deserializace polymorfních objektů

C# JSON Serializace a deserializace polymorfních objektů -rozepsané


Po dlouhé době jsem narazil na zajímavý problém. Potřebuji uložit data do formátu JSON ale každá datová položka je jiný typ. Jedná se o tzv. polymofní typ. Například chci si uložit databázi zvířat (animals) a mám definovaný obecný objekt animal a pak mám definované konkrétní typy Cat, Lion, Horse. A každý typ má trochu jiné vlastnosti.

Podívejme se na můj konkrétní případ: Mám pole nějakých objektů, které představují nějaké nastavení. Každá položka v poli má své jméno Name a hodnotu Value.

public class OptionValue
    {
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public object Value { get; set; }
    }

Defaultní JSON serializér mi udělal jednoduchý JSON, ale nešlo rozeznat Typy Value. Udělal jsem si pro každý datový typ speciální variantu:


[DataContract]    
public class IntValue
{
 public IntValue()
 {
 }

 public IntValue(string name)
 {
  Name = name;
 }

 [DataMember]
 public string Name { get; set; }

 [DataMember]
 public new Int32 Value { get; set; }
}

[DataContract]
public class BoolValue
{
 public BoolValue()
 {
 }

 public BoolValue(string name)
 {
  Name = name;
 }

 [DataMember]
 public string Name { get; set; }

 [DataMember]
 public new bool Value { get; set; }
}

[DataContract]
public class StringValue
{
 public StringValue()
 {
 }

 public StringValue(string name)
 {
  Name = name;
 }

 [DataMember]
 public string Name { get; set; }

 [DataMember]
 public new String Value { get; set; }
}

[DataContract]
public class TimeValue
{
 public TimeValue()
 {
 }

 public TimeValue(string name)
 {
  Name = name;
 }

 [DataMember]
 public string Name { get; set; }

 [DataMember]
 public new TimeSpan Value { get; set; }
}

[DataContract]
public class DateValue
{
 public DateValue()
 {

 }

 public DateValue(string name)
 {
  Name = name;
 }

 [DataMember]
 public string Name { get; set; }

 [DataMember]
 public new DateTime Value { get; set; }
}

Pokud použiji defaultní serializér:

msg = Request.CreateResponse(HttpStatusCode.OK,array, "application/json");

dostanu výsledek, kde nevím, jakého typu mám položky.



[{"Name":"DefaultSection","Value":"SatelliteHolder"},{"Name":"FillInterfaceName","Value":"Bonus"},{"Name":"FillFilterName","Value":"SATELLITE FILL"},{"Name":"FillSection:Position","Value":"end"},{"Name":"FillSection:Position","Value":"end"},{"Name":"FillSection:Position","Value":"end"},{"Name":"ConfigFillSectionType","Value":"SpotsetHolder"},{"Name":"MinAllowFillDistance","Value":240},{"Name":"MinGroupFillDistance","Value":10},{"Name":"SeparationFilterName","Value":"SATELLITE SEPARATION"},{"Name":"FillFilterSkip","Value":"SATELLITE SKIP"},{"Name":"ConfigSkipSectionType","Value":"SpotsetHolder"},{"Name":"Performance","Value":false},{"Name":"VisibleSections","Value":"HourHeader|SatelliteHolder"}]
Na rozlišení typů jsem si našel jiný serializer, který se nacháyí v System.Web.Extensions.
string json = new JavaScriptSerializer(new TypeResolver()).Serialize(o);
msg = Request.CreateResponse(HttpStatusCode.OK,json, "application/json");
K tomu musíte ješte připsat JavaScriptTypeResolver:
public class TypeResolver : JavaScriptTypeResolver
{
public override Type ResolveType(string id)
{
 if (id == "string")
 {
  return new StringValue().GetType();
 }
 else if (id == "int")
 {
  return new IntValue().GetType();
 }
 else if (id == "bool")
 {
  return new BoolValue().GetType();
 }
 else if (id == "float")
 {
  return new FloatValue().GetType();
 }
 else if (id == "time")
 {
  return new TimeSpan().GetType();
 }
 else if (id == "date")
 {
  return new DateTime().GetType();
 }

 return new object().GetType();
}

public override string ResolveTypeId(Type type)
{
 if (type.Name == "StringValue")
  return "string";
 else if (type.Name == "IntValue")
  return "int";
 else if (type.Name == "BoolValue")
  return "bool";
 else if (type.Name == "FloatValue")
  return "float";
 else if (type.Name == "TimeValue")
  return "time";
 else if (type.Name == "DateValue")
  return "date";

 return "anyType";
}
Zpětně jde výsledek zase serializovat:
object obj = new JavaScriptSerializer(new TypeResolver()).Deserialize<Options>(json);
Výsledek už nevypadá tak hezky, ale informaci o typu zde již máme.
"[{\"__type\":\"string\",\"Name\":\"DefaultSection\",\"Value\":\"SatelliteHolder\"},{\"__type\":\"string\",\"Name\":\"FillInterfaceName\",\"Value\":\"Bonus\"},{\"__type\":\"string\",\"Name\":\"FillFilterName\",\"Value\":\"SATELLITE FILL\"},{\"__type\":\"string\",\"Name\":\"FillSection:Position\",\"Value\":\"end\"},{\"__type\":\"string\",\"Name\":\"FillSection:Position\",\"Value\":\"end\"},{\"__type\":\"string\",\"Name\":\"FillSection:Position\",\"Value\":\"end\"},{\"__type\":\"string\",\"Name\":\"ConfigFillSectionType\",\"Value\":\"SpotsetHolder\"},{\"__type\":\"int\",\"Name\":\"MinAllowFillDistance\",\"Value\":240},{\"__type\":\"int\",\"Name\":\"MinGroupFillDistance\",\"Value\":10},{\"__type\":\"string\",\"Name\":\"SeparationFilterName\",\"Value\":\"SATELLITE SEPARATION\"},{\"__type\":\"string\",\"Name\":\"FillFilterSkip\",\"Value\":\"SATELLITE SKIP\"},{\"__type\":\"string\",\"Name\":\"ConfigSkipSectionType\",\"Value\":\"SpotsetHolder\"},{\"__type\":\"bool\",\"Name\":\"Performance\",\"Value\":false},{\"__type\":\"string\",\"Name\":\"VisibleSections\",\"Value\":\"HourHeader|SatelliteHolder\"}]"

pátek 22. března 2013

Věčný problém s parsováním parametrů URL

Opakovaně řeším v serverové službě problém s parsováním parametrů.


  1. Když jsem si službu napsal jako WCF REST, tak jsem zjistil, že WCF neumí pracovat s dynamickým počtem parametrů. Tak jsem dynamické parametry zakódoval do stringu. Vše se zdálo v pohodě až do chvíle, kdy se v parametrech objevilo '/' nedokáže WCF příjmout HTTP request. Vadí mu lomítko navíc. Zde jsem řešení nenašel
  2. Když jsem službu napsal jako HttpListener, tedy pouze jednoduchý zachytávač HTTP requestů, tak jsem narazil na podobný problém se znakem '&'.

    Parametry jsem si naparsoval pomocí utility:
    NameValueCollection qscoll = HttpUtility.ParseQueryString(querystring);
    http://localhost:8128/Action/ActionExecute/command=c:/notepad&.exe
    Dostal jsem výsledek:
    0) command=c:\notepad
    1) null = .exe
    Jak z toho ven (sto hoven)?
Nakonec jsem napsal dotaz na stackoverflow:
Parse Query string

Řešení je velmi jednoduché. Musíte dostat korektní QueryString, který má nahrazené řídící znaky escape sekvencí.

pondělí 18. března 2013

Kroutím hlavou

string stanice="frekvence1";

Public string get()
{
string stanice="kiss";
return stanice;
}

čtvrtek 7. března 2013

Window Manager

Přemýšlím, jak do aplikačního frameworku MEF, Prism začlenit Windows manager


Inspirace:
http://www.codeproject.com/Articles/249261/How-To-Embed-An-Application-Into-a-Docking-Library


pátek 23. listopadu 2012

WCF ROUTING


                http://msdn.microsoft.com/en-us/library/ee517421.aspx

čtvrtek 8. března 2012

WCF - RESTFULL - service - webová služba

Do našeho serveru budeme přidávat dolaší WCF službu. Tentokráte se bude jednat o služby přístupnou přes HTTP  protokol. Jedná se o klasickou webovou službu.

Podívejme se na příklad:
Vytvoříme si nový ServiceContract.
[ServiceContract]
public interface IEventService
{          
        
  [OperationContract]
  [WebGet(UriTemplate = "EventInfo/{exe_name}", ResponseFormat = WebMessageFormat.Xml)]
  EventInfo GetEventInfo(string exe_name);

}
Způsob volání přes protokol HTTP se konfiguruje pomocí atributu WebGet. Bude se jednat o volání přes HTTP příkaz GET. Kdybychom chtěli využít jiných HTTP příkazů, můžeme využít atributu WebInvoke pro jejich konfiguraci.
[OperationContract]
[WebInvoke(Method = "PUT", UriTemplate = "/customer/{id}")]
public void PutCustomer(int id, Customer customer)
{
   
}
 
[OperationContract]
[WebInvoke(Method = "DELETE", UriTemplate = "/customer/{id}")]
public void DeleteCustomer(int id)
{
  
        
}
Podívejme zpět se na první příklad, kde funkce GetEventInfo vrací třídu EventInfo. Zajisté vás zajímá, v jakém formátu se vrátí odpověď od serveru. Formát si můžete přepnout buď přepínačem ResponseFormat = WebMessageFormat.Xml nebo přepínačem ResponseFormat = WebMessageFormat.Json. Zaměřme se na XML formát. Mám jednoduchou třídu:
[DataContract]    
public class EventInfo
{   
  [DataMember]
  public string Name
  {
    get;            
    set;            
  }
}
Server mi vrátí XML a názvy tagů jsou totožné z názvy tříd. Server vrátí výsledné XML jako:
<EventInfo>
<Name>AKCE</Name>
</EventInfo>
To je dobré, ale často mohu potřebovat pojmenovat tagy nějakým vlastním jménem. Jakým způsobem mohu ovlivnit názvy tagů?
[DataContract(Name="MyEventInfo")]    
public class EventInfo
{   
  [DataMember(Name="Jmeno")]
  public string Name
  {
    get;            
    set;            
  }
}

Pokud do atributu DataContract přidáte parametr Name, dostane tag ve výstupním XML toto jméno. To samé se stane, když přidáte parametr Name do atributu DataMember.Ze serveru se mi vrátí XML:
<MyEventInfo xmlns="http://schemas.datacontract.org/2004/07/WCF8bcPgServices" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Jmeno>AKCE</Jmeno>
</MyEventInfo>
To je vše přátelé.

pátek 24. února 2012

WEB Request - GET

Potřeboval jsem zavolat jednoduchou službu na webu, kde jsem přes URL předal parametry. K tomu mi postačí HTTP dotaz typu GET.

WebRequest request = WebRequest.Create(service + invoke);
request.Method = "GET";
using (WebResponse response = request.GetResponse())
{
  using (Stream stream = response.GetResponseStream())
  {
    XmlTextReader reader = new XmlTextReader(stream);                    
  }
}

URL jsem si rozděli na URL služby - service a parametry volání - invoke. Dejte pozor na nepovolené znaky. Před odeslání prožeňte parametry url encoderem, který vám nahradí nepovolené znaky.

System.Web.HttpUtility.UrlEncode(url_encode);

Na straně serveru si nezapomeňte parametry dekódovat zpět.

System.Web.HttpUtility.UrlDecode(pars);