Milan Křepelka

Osobní blog

MCPD

clock May 15, 2010 00:36 by author Administrator

 Stal jsem se certifikovaným profesionálním vývojářem. Co dál, že by JAVA ?

 

 



Ovládání uživatelských kontrolů z jiného vlákna aneb InvokeRequired never-ending story

clock September 4, 2009 23:39 by author Administrator

Častým problémem .NET vývojářů, kteří se prvně setkávají s aplikacemi, jež mají pracovní vlákna, která svůj výsledek vrací zpět do GUI aplikace je výjimka InvalidOperationException s následujícím popisem :

Cross-thread operation not valid: Control 'result' accessed from a thread other than the thread it was created on. 

Položím si tedy otázku : Proč nastala tato výjimka ? A rovnou i odpovím : V .NETu lze obsluhovat kontroly - GUI prvky, pouze z vlákna které tyto controly vytvořilo. Pro lepší znázornění cvičný příklad aplikace :

  Standardní GUI aplikace, která má dlouhotrvající funkci vykonávající nějakou aplikační logiku. Protože je ta funkce dlouhotrvající, je potřeba ji provést jiném než hlavní (GUI) vláknu aplikace. Jinak by v průběhu jejího trvání grafické rozhraní "zamrzlo". Tedy mám hlavní formulář aplikace, na ní tlačítko, které spustí dlouho trvající funkci jež vrací stav o průbehu funkce do hlavního vlákna. Pro jednoduchost bude naše dlouhotrvající funkce jenom cyklus zvednutí čítače od 0 do 9 každou čtvrtsekundu a nastavení hodnoty čítače do labelu-result v hlavním formuláři. Programově to bude vypadat takto : 

 

private void runButton_Click(object sender, EventArgs e)
{
 System.Threading.Thread workThread = new System.Threading.Thread(longRunningFunction);
 workThread.Start();
}

private void longRunningFunction()
{
  for (int counter = 0; counter < 10; counter++)
  {
  System.Threading.Thread.Sleep(250);
  result.Text = counter.ToString();
  }
}

 

 

 

 

  Což je tedy z pohledu .NETu špatně a je potřeba to udělat jinak. Je  potřeba zajistit, aby změnu v GUI prvku zajistil kód, běžící ve vláknu, které daný kontrol vytvořilo. Tuto službu zajistí metoda Invoke kontrolu nad kterým provádím změnu.

 

 

 

 

  Kód bude upraven takto :

 

//delegát pro obnovovací funkci   

delegate void numberDelegate(int number); 

private void runButton_Click(object sender, EventArgs e)
{
    System.Threading.Thread workThread = new System.Threading.Thread(longRunningFunction);
    workThread.Start();

}

private void longRunningFunction()
{
    for (int counter = 0; counter < 10; counter++)
    {
      System.Threading.Thread.Sleep(250);

      // funkce, která obnoví obsah labelu
      refreshLabel(counter);
    }
}

public void refreshLabel(int resultValue)
{

      // kontrola jestli tento kód běží ve vlákně, ve kterém lze text labelu nastavit  

    if (result.InvokeRequired)
    {

      // opětné vyvolání této tunkce, akorát ve vlákně, ve kterém lze text labelu nastavit
      result.Invoke(new numberDelegate(refreshLabel), resultValue);
    }
    else
    {
       // nastavení textu labelu 

      result.Text = resultValue.ToString();
    }
}
   

 

Příklad ve VS 2005 najdete zde :  

 

CrossThread.zip (32,56 kb)



Welcome to BlogEngine.NET 1.5.0

clock April 2, 2009 09:00 by author Administrator

If you see this post it means that BlogEngine.NET 1.5.0 is running and the hard part of creating your own blog is done. There is only a few things left to do.

Write Permissions

To be able to log in to the blog and writing posts, you need to enable write permissions on the App_Data folder. If you’re blog is hosted at a hosting provider, you can either log into your account’s admin page or call the support. You need write permissions on the App_Data folder because all posts, comments, and blog attachments are saved as XML files and placed in the App_Data folder. 

If you wish to use a database to to store your blog data, we still encourage you to enable this write access for an images you may wish to store for your blog posts.  If you are interested in using Microsoft SQL Server, MySQL, VistaDB, or other databases, please see the BlogEngine wiki to get started.

Security

When you've got write permissions to the App_Data folder, you need to change the username and password. Find the sign-in link located either at the bottom or top of the page depending on your current theme and click it. Now enter "admin" in both the username and password fields and click the button. You will now see an admin menu appear. It has a link to the "Users" admin page. From there you can change the username and password.  Passwords are hashed by default so if you lose your password, please see the BlogEngine wiki for information on recovery.

Configuration and Profile

Now that you have your blog secured, take a look through the settings and give your new blog a title.  BlogEngine.NET 1.4 is set up to take full advantage of of many semantic formats and technologies such as FOAF, SIOC and APML. It means that the content stored in your BlogEngine.NET installation will be fully portable and auto-discoverable.  Be sure to fill in your author profile to take better advantage of this.

Themes and Widgets

One last thing to consider is customizing the look of your blog.  We have a few themes available right out of the box including two fully setup to use our new widget framework.  The widget framework allows drop and drag placement on your side bar as well as editing and configuration right in the widget while you are logged in.  Be sure to check out our home page for more theme choices and downloadable widgets to add to your blog.

On the web

You can find BlogEngine.NET on the official website. Here you'll find tutorials, documentation, tips and tricks and much more. The ongoing development of BlogEngine.NET can be followed at CodePlex where the daily builds will be published for anyone to download.

Good luck and happy writing.

The BlogEngine.NET team



Zápisník letů - beta verze

clock February 5, 2009 23:05 by author Administrator

Do zápisníku letů přibyly tyto novinky :

 Instalátor - stačí spustit. Ve windows Start Menu vznikne : Start -> Všechny programy -> Zápisník letů -> Zápisník letů. Odinstalace : Start menu -> Ovládací panely -> Přidat nebo odebrat programy

Tisk filtru - záznamy letů. Tak jak bylo v knižní formě. Tisknou se pouze označené záznamy. Označuje se 

  • vše - klávesouvou zkratkou CTRL - A
  • vybrané záznamy - klikem a tahem myši při okraji filtru. viz obrázek 

 

 

Zbýva mi udělat či upravit pár drobností. Ale rámcově mám myslím všechno. Nainstalujte prosím a napište seznam věcí co by vám ulehčily práci s programem. 

FlightBook.zip (7,56 mb)

 

x64.zip (1,38 mb)

x86.zip (1,38 mb)



Zápisník letů - alfa verze

clock January 4, 2009 01:47 by author Administrator

První alfa verze záznamníku letů

Co už je :

  • základní funkcionalita programu
  • grafická schémata
  • filtrování dat

 

Co ještě není :

  •  sumarizace dat, v našem případě sumarizace nalétaných hodin
  • část ze zápisníku letů, která se týka zápisů hodin na simulátorech
  • funkconalita, kterou si přál p. Kolísek a to tedy zobrazení dat, tak jak je v knižní formě - to tedy budu realizovat formou tiskové sestavy, tedy to bude opravdu vypadat tak jak je v knižní formě, ale chvilku mi to potrvá
  • instalátor

 

Instalace

 Formou nakopíruj a spusť. Zatím není hotový instalátor. Takže stačí si vytvořit adresář. Nakopírovat do něj všechno z tohoto zipu :

 

FlightBook.zip (15,58 mb)

Přečíst Dokumentace.doc 

Spustit FlightBook.exe.

 

Pohrajte si s tím a dejte vědět co je potřeba změnit, aby to bylo OK. Nejlépe formou příspěvku v tomto blogu, aspoň všichni uvidí všechno.

 

p.s. Je potřeba mít nainstalovaný Microsoft  .NET framework 2.0



MCTS

clock December 23, 2008 18:31 by author Administrator

Složil jsem úspěšně dvě certifikační zkoušky

  • Microsoft .NET Framework – Application Development Foundation
  • Microsoft .NET Framework 2.0 – Windows-Based Client Development

 

Tudíž jsem získal certifikát : Microsoft Certified Technology Specialist 



DirectoryWatcher

clock December 14, 2008 18:18 by author Administrator

DirectoryWatcher - sledovač adresáře/složky

Pro svoje soukromé účely jsem udělal program, který monitoruje události nad adresářem a zprávy o těchto událostech posílá na emailem.

Typy událostí

  • vytvoření souboru/adresáře
  • změna souboru/adresáře
  • přejmenování souboru/adresáře
  • smazání souboru/adresáře

 Program běží jako služba operačního systému DirectoryWatcher, takže nemá žádné grafické rozhraní.

Instalace 

Stací spustit tento soubor DirectoryWatcherSetup.msi (570,50 kb)

A potom ve službách systému nastartovat tuto službu. Nebo zrestartovat počítač. Každopádně je potřeba program nejdříve správně nakonfigurovat.

Konfigurace 

Program má konfigurační soubor, který nejdete v adresáři <WINDIR>\System32\DirectoryWatcher.exe.config. Po změně konfigurace je nutno službu zrestartovat.

Konfigurační položky

  • WatchDirectory - adresář, který chcete sledovat, nutné zadat
  • WatchMask - maska souborů, které chcete sledovat. *.* znamená vše, stačí ponechat
  • CreatedEventMailList - Cesta k souboru, ve kterém je seznam emailových příjemců pro událost typu - vytvoření adresáře/souboru, možno vynechat - ale lépe zadat, právě kvůli tomu program vzniknul
  • ChangedEventMailList - Cesta k souboru, ve kterém je seznam emailových příjemců pro událost typu - změna adresáře/souboru, možno vynechat
  • RenamedEventMailList - Cesta k souboru, ve kterém je seznam emailových příjemců pro událost typu - přejmenování adresáře/souboru, možno vynechat
  • RenamedEventMailList - Cesta k souboru, ve kterém je seznam emailových příjemců pro událost typu - přejmenování adresáře/souboru, možno vynechat
  • DeletedEventMailList - Cesta k souboru, ve kterém je seznam emailových příjemců pro událost typu - smazání adresáře/souboru, možno vynechat
  • ErrorRecipients - Cesta k souboru, ve kterém je seznam emailových příjemců pro událost typu - chyba, možno vynechat
  • MailDelimiter - Oddělovač seznamu emailových příjemců. Standardně je to středník, ale není potřeba to měnit. Záznam v souboru potom tedy vypadá takto : prijemce1@server.domena;prijemce2@server.domena, stačí ponechat
  • WatcherDirectoryFromSender - emailová adresa pod, kterou se hlásí program, když odesílá emailovou zprávu, nutno zadat
  • WatcherDirectoryFromSenderDisplayName - zobrazované jméno pod, kterým se hlásí program, když odesílá emailovou zprávu, možno vynechat
  • SmtpHost - Server odchozí pošty, nutno zadat
  • SmtpUserName, název smtp účtu, možno vynechat - záleží na nastavení smtp serveru
  • SmtpUserPassword, heslo k smtp účtu, , možno vynechat - záleží na nastavení smtp serveru
  • SmtpHostPort - smtp port, stačí ponechat, pokud není smtp server speciálně nastaven
  • SenderDelay - interval posílání emalových zpráv
  • OnlyDirectoriesNotification - Příznak, že se bude hlídání adresáře týka pouze adresářů, ne souborů. Možné hodnoty True/False
  • LogFilePath - cesta k logovacímu souboru

Logování

Program všechny svoje informační zprávy a chyby hlásí do svého logovacího souboru. V defaultním nastavení do c:\DirectoryWatcher.log . Pokud vám tedy program nefunguje je potřeba se kouknout do tohoto souboru. 

Zprávy 

Emailová zpráva, potom vypadá takto :

Předmět : DirectoryWatcher

Zpráva : <Typ události> <Celá cesta k souboru/adresáři>

Poznámky k programu

 Není dobré sledovat adresář nad kterým je opravdu velký "provoz", nebo třeba celý disk (C:\).  Systémová komponenta na které je program založen potom generuje chyby. 

Zdrojové kódy 

Pro programátory zanechám i zdrojové kódy. Upravujte si program dle libosti.

 DirectoryWatcher.zip (389,17 kb)



Věčně ztracená snippetka

clock December 11, 2008 02:39 by author Administrator

Často ztrácím, při přechodu z počítače na počítač, snippetku. Která v kódu vypadá takto :

  #region Constructors
  #endregion
   
  #region Private members
  #endregion
   
  #region Public members
  #endregion
 
  #region Private methods
  #endregion
   
  #region Public methods
  #endregion

Tak si ji dám sem, a už se mi nikdy neztratí. Snad .... Smile 

 baseclassregions.snippet (911,00 bytes)



Ověřování xml souboru

clock October 28, 2008 21:34 by author Administrator

Jedna z možností jak validovat xml soubory dle své šablony. Těch možností je mnoho. Otázka je, jak výkonostně by na tom bylo toto řešení. Netestoval jsem.

 

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.Schema;

namespace XmlValidation
{

    class Program
    {
        static void Main(string[] args)
        {
            string xsd_template = @"C:\Program Files\Microsoft Visual Studio 8\xml\Schemas\DotNetConfig.xsd";
            XmlTemplateValidator configuration_validator = new XmlTemplateValidator(new Uri(xsd_template).ToString());
            Console.WriteLine(configuration_validator.Validate("App.config"));
            Console.ReadLine();
        }
    }

    /// <summary>
    /// Validate xml file
    /// </summary>
    public class XmlTemplateValidator
    {
        /// <summary>
        /// Validation success flag
        /// </summary>
        private bool isValidationOk;
        // Schema set
        private XmlSchemaSet schemaSet;
        // Set the validation settings.
        private XmlReaderSettings settings;

        public XmlTemplateValidator(string TemplateUri)
        {
            isValidationOk = true;
            schemaSet = new XmlSchemaSet();
            schemaSet.Add(string.Empty, TemplateUri);
            settings = new XmlReaderSettings();
            settings.ValidationType = ValidationType.Schema;
            settings.Schemas = schemaSet;
            settings.ValidationEventHandler += new ValidationEventHandler(settings_ValidationEventHandler);
        }

        /// <summary>
        /// Validation callback
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">EventArg</param>
        private void settings_ValidationEventHandler(object sender, ValidationEventArgs e)
        {
            if (e.Severity == XmlSeverityType.Error)
            {
                isValidationOk = false;
            }
        }

        /// <summary>
        /// Validate Xml file
        /// </summary>
        /// <param name="XmlFile">XmlFilePath</param>
        /// <returns>Success</returns>
        public bool Validate(string XmlFile)
        {
            if (!System.IO.File.Exists(XmlFile)) throw new System.IO.FileNotFoundException("File not found", XmlFile);
            isValidationOk = true;
            XmlReader reader = XmlReader.Create(XmlFile, settings);
            while (reader.Read())
            {
                if (isValidationOk == false)
                {

                    reader.Close();
                    return false;
                }
            }
            reader.Close();
            return true;
        }
    }
}

XmlValidation.zip (42,51 kb)



Form1 Form2 problém

clock October 27, 2008 23:15 by author Administrator

C# - Form1 Form2 problém

Relativně často se na mém oblíbeném fóru objevuje začátečnická otázka typu :

Form1 otevřu jako dialog Form2. Jak prostřednictvím Form2 změním hodnoty ve Form1

A taky nevím, jak například zjistím obsah textboxu v okne Form1 z okna Form2.


Když si udělám v aplikaci C#, kromě form1 další formulář form2 a ně něj položím třeba prvek textBox, chtěl bych se na něj dostat i z form1

Vytvořím a rozložím tedy tento problém a vysvětlím několik z možných řešení. Problém : Mám hlavní formulář aplikace na kterým je nějakým způsobem zobrazen uživatel a chci na tlačítko zobrazit formulář s informacemi o uživateli. Tam data zmodifikovat a vrátit do hlavního formuláře jak je na obrázku :

Formuláře

 

 

Pojmenuji tedy hlavní formulář jako MasterForm a formulář uživatele jako UserForm. Problém rozložím do úkolů :

 

  1. Jak dostat data z MasterForm do UserForm
  2. Jak dostat data z UserForm do MasterForm

 

A nastíním několik řešení

Veřejné uživatelské prvky

 

Jedno z možných řešení je uživatelským prvkům sloužící jako zdroje dat nastavit vlastnost Modifiers na public v obou formulářích. Kod by byl potom vyjádřen takto (obluha událost stisknutí tlačítka na MasterForm):

 

private void showAndGetUserButton_Click(object sender, EventArgs e)
{
// úkol 1
UserForm user_form = new UserForm();
 user_form.NameUserTextBox.Text = this.NameUserTextBox.Text;
 user_form.BirthDateDateTimePicker.Value = this.BirthDateDateTimePicker.Value;
 user_form.ChildNumberTextBox.Text = this.ChildNumberTextBox.Text;
 if (user_form.ShowDialog() == DialogResult.OK)
  {
  // úkol 2
  this.NameUserTextBox.Text = user_form.NameUserTextBox.Text;
  this.BirthDateDateTimePicker.Value =   user_form.BirthDateDateTimePicker.Value;
  this.ChildNumberTextBox.Text = user_form.ChildNumberTextBox.Text;
 }
}

 

Jednoduché, bezpracné a zcela krátkozraké řešení. Proč krátkozraké ? Protože zpravidla uživatel má nějaké jméno. Datum narození nebude starší 200 let a nebude z budoucnosti. Počet dětí nebude záporné číslo. Nazvu toto aplikační logikou, kterou je nutnou zkontrolovat při návratu z UserForm do MasterForm. Kontrolu této logiky lze potom různě rozdělit mezi MasterForm a UserForm o čemž není primárně tento článek. Jde o to, že tento způsob jde proti dobrým programátorským mravům z hlediska zapouzdření objektu. Zbytečně zveřejňujeme prvky formuláře aniž by k tomu byl vážný důvod. Navíc můžeme potřebovat vytvářet a zobrazovat UserForm na vícero místech a třeba budeme potřebovat s počtem dětí pracovat jako s číslem, takže bychom museli všude převádět na číslo. Vysvětlím proto lepší způsob.

 

Properties 

 

Rozhodně lepším způsobem řešení je pro každou naší informaci : jmého uživatele, datum narození a počet dětí použít veřejnou property, která spolupracuje z konkrétním uživatelským prvkem v každém z obou z formulářů :

public string Name
{
 get
 {
  return nameUserTextBox.Text;
 }
 set
 {
  nameUserTextBox.Text = !string.IsNullOrEmpty(value) ? value : string.Empty;
 }
}

public DateTime BirthDate
 {
  get
 {
  return birthDateDateTimePicker.Value;
 }
 set
 {
  birthDateDateTimePicker.Value = value;
 }
}

public int ChildNumber
 {
 get
 {
  int child_number = int.MinValue;
  if (int.TryParse(childNumberTextBox.Text, out child_number))
   {
    return child_number;
   }
  else
  {
   return int.MinValue;
  }
 }
 set
 {
  this.childNumberTextBox.Text = value.ToString();
 }
}

 

Naše dva úkoly potom budou vypadat takto:

 

// úkol 1
 UserForm user_form = new UserForm();
 user_form.Name = this.Name;
 user_form.BirthDate = this.BirthDate;
 user_form.ChildNumber = this.ChildNumber;
 if (user_form.ShowDialog() == DialogResult.OK)
 {
  // úkol 2
  this.Name = user_form.Name;
  this.BirthDate = user_form.BirthDate;
  this.ChildNumber = user_form.ChildNumber;
 }

 

Takovýto kód je potom čistší, lépe spravovatelnější a hlavně ve větším měřítku srozumitelnější. I další výhody má, ale v rámci rozumné krátkosti to podrobněji popisovat nebudu.

Malý "problém" výše uvedeného přístupu je ten, že by to takto zkušenější programátor nenapsal. Ta data by zabalil do třídy uživatel a přes property by si předal jenom toho uživatele. Tedy princip stejný. 

 

Předávání odkazů na MasterForm


 

Ještě jednu techniku zde zmíním. Z mého pohledu implikující spíš problém v návrhu aplikace, ale někdy se může hodit o tomto vědět.
Pokud bych chtěl pracovat v UserFormu s MasterFormem, předal bych si do UserFormu na MasterForm odkaz. Já bych to udelal konstruktorem. A to zkráceně takto:

 public class UserForm:Form
{
 private MasterForm masterForm;

 public UserForm(MasterForm masterForm)
 {
  // předání odkazu
  this.masterForm = masterForm;
 }
 public void delejNecoVMasterFormu()
 {
  this.masterForm.Name = “Vlášek Karel”;
 }
}

public class MasterForm:Form
{
 private void showAndGetUserButton_Click(object sender, EventArgs e)
 {
  // předání kostruktorem
  UserForm user_form = new UserForm(this);
  if (user_form.ShowDialog() == DialogResult.OK)
  {
  // tady můžu a nemusím něco dělat
  }
 }
}

 

Závěr

Chtěl jsem ukázat na cvičném příkladu několik jednoduchých možností jak si předávat data mezi formuláři. Pouze jen a o to mi šlo. Zkušený programátor by totiž problematiku zobrazení uživatele ve formulářích řešil vytvořením třídy uživatel …., ale to už je jiný příběh.
Projekt na hraní s verzi Properties pro VS 2005 je zde.

Form1Form2Problem.zip (42,81 kb)