Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Diskuze: WPF - Binding Validation Exception Rule

Aktivity
Avatar
Petr Nymsa
Tvůrce
Avatar
Petr Nymsa:12.12.2013 19:56

Ahoj, mám dotaz nejspíše na ty zdatnější ve WPF. Snažím se rozběhat Binding validaci. Tj, například z textboxu binduju do property a v set vyvolám výjimku (špatná hodnota apod,..). Pokud tohle vyzkouším u property typu INT, vše funguje jak očekávám až na jednu věc. Chvilku aplikace zamrzne, po rozmrznutí textbox zčervená a je tam i příslušný tooltip popisující chybu.

Pokud ovšem změním property na typ STRING aplikace spadne - výjimka nebyla zachycena. Vše mám z knížky Visual C# Krok za krokem. Podobné ukázky mají i na MSDN apod.

Properties

int price;
        public int Price
        {
            get { return price; }
            set
            {

             price = value;

            }
        }

        string foo;
        public string Foo
        {
            get { return foo; }
            set
            {
                if (string.IsNullOrEmpty(value))
                    throw new ArgumentException("Chyba, oprav se prosím");
                else
                    foo = value;
            }
        }

Styl erroru

<Style x:Key="ErrorStyle" TargetType="Control">
          <Style.Triggers>
              <Trigger Property="Validation.HasError" Value="True">
                  <Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self},Path=(Validation.Errors)[0].ErrorContent}" />
              </Trigger>
          </Style.Triggers>
      </Style>

a kus XAML s textboxem

<TextBox>
               <TextBox.Text>
                   <Binding Path="Price">
                       <Binding.ValidationRules>
                           <ExceptionValidationRule/>
                       </Binding.ValidationRules>
                   </Binding>
               </TextBox.Text>
           </TextBox>

Máte někdo nějaké rady / nápady ? Díky moc !

Odpovědět
12.12.2013 19:56
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Petr Nymsa
Tvůrce
Avatar
Petr Nymsa:12.12.2013 21:11

Věděl by někdo ? :) Nebo jsem zde jediný kdo využívá Data Binding ? :D

Nahoru Odpovědět
12.12.2013 21:11
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Jan Vargovský
Tvůrce
Avatar
Odpovídá na Petr Nymsa
Jan Vargovský:12.12.2013 21:20

Počkej pár týdnů, tě doženu :P

 
Nahoru Odpovědět
12.12.2013 21:20
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na Jan Vargovský
Petr Nymsa:12.12.2013 21:28

Já prostě mám zase extra chybu. Všude mají úplně stejné řešení a zdá se že to funguje, mě za boha ne :@

Nahoru Odpovědět
12.12.2013 21:28
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Vonta
Neregistrovaný
Avatar
Vonta:12.12.2013 21:59

No,, a je správně vyhazovat výjimku v tomhle případě?
Já jsem si vždycky myslel, že výjimky se volej v případě, že to spadne někam, kde by za normálního běhu se to vůbec nedostalo, což není ale ověřování zadání textu...
(nikdy jsem ty výjimky podrobně nestudoval, takže se rád poučím)

Šlo by to třeba tak, že bys tam měl jinou property IsError a na tu bys bindoval přítomnost tooltipu s textem, barvu rámečku, atd..

 
Nahoru Odpovědět
12.12.2013 21:59
Avatar
Petr Nymsa
Tvůrce
Avatar
Petr Nymsa:12.12.2013 22:00

Asi "zčásti" vyřešeno. Vypnul jsem ve VS při Debug modu v nastavení Exceptions - ArgumentException - odškrtnutí User-Unhandled. Ale to se mi jeví jako blbost největší, každopádně se to tváří jako funkční

Nahoru Odpovědět
12.12.2013 22:00
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na
Petr Nymsa:12.12.2013 22:03

Ano je to jeden z několika postupů :)

Nahoru Odpovědět
12.12.2013 22:03
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Kit
Tvůrce
Avatar
Odpovídá na
Kit:12.12.2013 22:09

Výjimky se vyhazují i tehdy, když uživatel zadá nevalidní vstup.

Nahoru Odpovědět
12.12.2013 22:09
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
coells
Tvůrce
Avatar
Odpovídá na Petr Nymsa
coells:13.12.2013 0:06

Máš dvě chyby:

  1. chybí ti notifikace o změně property
  2. chybí ti value converter

První problém se dá vyřešit:

  1. buď místo C# property používej DependencyProperty
  2. nebo implementuj INotifyProper­tyChanged interface a v setteru vyvolej událost PropertyChanged

Jinak ti nebude fungovat two-way binding.

Ta chyba, na kterou se ptáš, je kvůli null hodnotě:

  1. buď na bindingu nastav TargetNullValu­e={x:Static clr:String.Empty}
  2. nebo implementuj vlastní IValueConverter, kde null zpracuješ korektně
 
Nahoru Odpovědět
13.12.2013 0:06
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na coells
Petr Nymsa:13.12.2013 7:02

INotifyProper­tyChanged je potřeba pro TwoWay ? Mě funguje i bez něho. Jinak jej samozřejmě využívám :).

Ono právě podle X různých tutoriálů popisují různé způsoby, jeden ze způsobů je vyhazování výjimky a ošetření přesně (nebo alespoň se mi to tak zdá) jak to mám já. Díky mrknu na to :)

Nahoru Odpovědět
13.12.2013 7:02
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na coells
Petr Nymsa:13.12.2013 7:11

Například zde: http://blog.magnusmontin.net/…tion-in-wpf/ + to samé mám v té knize. Výjimka se nezachytí a aplikace spadne. Když vypnu User-Handling vše funguje jak má

Nahoru Odpovědět
13.12.2013 7:11
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Petr Nymsa
Tvůrce
Avatar
Petr Nymsa:13.12.2013 7:16

Omlouvám se za spam :) Nefunguje to ještě korektně. Ta validace je strašně pomalá a chvilku aplikace zamrzne

Nahoru Odpovědět
13.12.2013 7:16
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
coells
Tvůrce
Avatar
Odpovídá na Petr Nymsa
coells:13.12.2013 10:36

To, co ukazuje, je nejhorší způsob, jak to dělat. WPF podporuje binding na C# properties jen kvůli zpětné kompatibilitě. Takže ti to nikdy nebude fungovat "korektně", to je korektní chování. Používej radši DependencyProperty a vlastní ValidationRule

Vyzkoušel jsem si to v projektu a funguje to dobře.

 
Nahoru Odpovědět
13.12.2013 10:36
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na coells
Petr Nymsa:13.12.2013 11:01

Jako i pro klasicky DataBinding využívat DependencyProperty ? Doteď si vždy implmenetuju INotifyProper­tyChanged, případně dále využívám Converter, DependencyProperty využívám u UserControls kde potřebuju nějaké vlastnosti bindovat

Nahoru Odpovědět
13.12.2013 11:01
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
coells
Tvůrce
Avatar
Odpovídá na Petr Nymsa
coells:13.12.2013 11:04

Ano, všude. WPF umí binding přes reflections a všude to ukazují, jak je to cool. Ale primární motivace pro tuhle featuru byla, abys mohl na WPF formuláře napojit už existující kód, kam nemůžeš dát DP.

Pokud píšeš nový kód, všude používej DependencyPro­perties. Jsou rychlé a umí toho mnohem víc - ale hlavně se chovají jako opravdové properties, umí dědit, vyvolat update/measure/a­rrange cyklus, atd.

 
Nahoru Odpovědět
13.12.2013 11:04
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na coells
Petr Nymsa:13.12.2013 11:23

Byl by jsi ochotný mi poslat ukázkový ViewModel kde implementuješ DependecyProperty apod ?

Nahoru Odpovědět
13.12.2013 11:23
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
coells
Tvůrce
Avatar
coells:13.12.2013 11:52

ViewModel je jen konceptuální vrstva, nemá tušení o View (XAML). Používej na ní buď field nebo DP, to je celé. Zdrojáky sdílet nemůžu, jsou důvěrné.

 
Nahoru Odpovědět
13.12.2013 11:52
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na coells
Petr Nymsa:13.12.2013 12:01

No co jsem pochopil MVVM, tak View binduje právě z ViewModel. Já nepotřebuju žádné opravdové zdrojové kódy :) Jen jestli by jsi nebyl (třeba časem) ochotný poslat nějaký příklad (učbenicový)

Nahoru Odpovědět
13.12.2013 12:01
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
coells
Tvůrce
Avatar
Odpovídá na Petr Nymsa
coells:13.12.2013 12:03

Ano, View binduje se na ViewModel, zatímco ViewModel nevidí o View. Jednoduše používej DP na ViewModelu i View a nepoužívej C# properties.

 
Nahoru Odpovědět
13.12.2013 12:03
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na coells
Petr Nymsa:13.12.2013 12:06

Mě osobně zatím přijde lepší využívat C# Properties. Jelikož definice DP

public static readonly DependencyProperty MyCustomProperty =
DependencyProperty.Register("MyCustom", typeof(string), typeof(Window1));
public string MyCustom
{
    get
    {
        return this.GetValue(MyCustomProperty) as string;
    }
    set
    {
        this.SetValue(MyCustomProperty, value);
    }
}

mě přijde strašně zdlouhavá a i obyčejná malá třída se 3 properties najednou nabobtná. Stále nevidím větší výhody, pokud tedy nepotřebuju validaci

Nahoru Odpovědět
13.12.2013 12:06
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
coells
Tvůrce
Avatar
Odpovídá na Petr Nymsa
coells:13.12.2013 12:07

Jinak ještě jedna věc. Já se zpočátku taky DP vyhýbal, protože mi přišly jako složitý mechanismus. Jenže pak jsem se koukal, jak jsou implementované a zjistil jsem, že jsou opravdu výhodnější.

 
Nahoru Odpovědět
13.12.2013 12:07
Avatar
coells
Tvůrce
Avatar
Odpovídá na Petr Nymsa
coells:13.12.2013 12:10

No tak to jsi nepsal opravdovou aplikaci, která má tunu tříd :-D Argument, že něco nabobtná funguje jen u projektů, které si napíšeš za hodinu. U větších aplikací to prostě nabobtná.

Jo a nepoužívej type-safe konverze, správně je to (string)GetVa­lue(MyCustomPro­perty).

 
Nahoru Odpovědět
13.12.2013 12:10
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na coells
Petr Nymsa:13.12.2013 12:13

Kód jsem zkopíroval :). A ne nebyla to aplikace na hodinu :) Nevidím v tom větší výhody (zatím). Binding kolekcí a properties mi funguje i přes klasické C# Property, propojím je tedy s ViewModelem. DP jsem využíval u vlastních Controls, kde jsem potřeboval aby nové vlastnosti Controlky šli Bindovat. Mrknu na to, díky :) Ale asi zůstanu ještě u klasických C# vlasntostí a implementací rozhraní

Nahoru Odpovědět
13.12.2013 12:13
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
coells
Tvůrce
Avatar
Odpovídá na Petr Nymsa
coells:13.12.2013 12:47

To, že jsi kód zkopíroval, ještě neznamená, že je správně ;-)

 
Nahoru Odpovědět
13.12.2013 12:47
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na coells
Petr Nymsa:13.12.2013 17:26

Já ho ani netestoval :) Chtěl jsem poukázat na to že oproti klasické C# Property která je na 2 řádky mám s DP několik řádků

Nahoru Odpovědět
13.12.2013 17:26
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
coells
Tvůrce
Avatar
Odpovídá na Petr Nymsa
coells:13.12.2013 17:38

No jo, jenže takhle to nemůžeš brát. To rovnou přestaň používat WPF a zůstaň u WinForms...

Celé WPF je optimalizované pro použití DependencyPro­perties, RoutedEvents a Commands. Stejně tak můžeš říct, že budeš používat eventy místo RoutedEvents a delegáty místo Commands.

V editoru stačí napsat propd a stisknout tab, zbytek už se dopíše sám (kromě metadat, která mají v šabloně špatně). Stejně tak to asi opisuješ z nějakých blogů, ale to jsou nespolehlivé zdroje informací, kdo myslíš, že je píše?

Když jsem vyvíjel obrovskou aplikaci pro WPF, ještě nebyly žádné blogy ani diskuze ani MVVM pattern. Jediný nástroj, který jsem měl, byl Reflector. Takže když něco nefungovalo, musel jsem kopat ve WPF. Také jsem reportoval asi 3 bugy do Microsoftu a nebyla sranda zjistit, jestli to mám špatně já nebo WPF.

Pionýrem slepých uliček byl Jára Cimrman, ale ty už si nemusíš procházet tím mortiriem, kterým si prošli ostatní, když bylo WPF v začátcích. Když dáš na moje rady, půjde ti to snáze a lépe. Když nedáš, tak nedáš, je to tvůj kód, ale až budeš psát další dotaz do diskuze, že něco nejde, vzpomeneš si na mě :-)

 
Nahoru Odpovědět
13.12.2013 17:38
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na coells
Petr Nymsa:13.12.2013 18:12

Mám knihu od Charlese Petzolda - Mistroství ve WPF. Celkově mě i uráží, že si myslíš že to slepě využívám. Pravdou je že s XAML jsem se poprvé setkal u MODERN UI aplikací (Windows 8). DataBinding mi i lidé z Microsoftu v různých sample code ukazovali takto. Já na tvé rady dávám, ale stále v tom nevidím extra výhodu mít místo 2 řádků kódu, napsaných mnohem více.

Teď jsem si něco málo o DP přečetl z již zmíněné knihy. Je opravdu potřeba nastavovat všechny její metadata apod ? Vždyť než si nadefinuju i jednoduchý Model tak se upíšu. Přeci když potřebuji Binding (OneWay i TwoWay) implementuju INotifyProper­tyChanged, přiřadím DataContext a svážu prvky s danými Properties, proč je při těchto požadavích lepší využít DP ?

Nahoru Odpovědět
13.12.2013 18:12
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
coells
Tvůrce
Avatar
Odpovídá na Petr Nymsa
coells:13.12.2013 18:39

Skvělé knihy jsou Essentials WPF a WPF Unleashed. A Petzold... kupoval jsem ji také. Jeho knihy jsou to nejpříšernější, co jsem kdy viděl, podle mě vyhozené peníze.

Výhodou používání DP je, že na nich celé WPF stojí. Začal jsi tohle vlákno, protože ti něco nefungovalo. To něco se dá napsat ve WPF asi pěti způsoby (jako skoro všechno ve WPF) a já ti odpověděl, že sis vybral nejhorší způsob, jak to napsat, protože je to tam kvůli zpětné kompatibilitě. Nejlepší způsob, jak to napsat, je používání DP, protože nebudeš muset psát další vlákna, co ti kde zase nefunguje. Je to dostatečně výhodné?

Pokud si myslíš, že se upíšeš, tak se těš, protože WPF je o upisování se. Než všechno nadefinuješ a propojíš, tak napíšeš tunu kódu ve srovnání s WinForms.

 
Nahoru Odpovědět
13.12.2013 18:39
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na coells
Petr Nymsa:13.12.2013 18:45

Dobrá ale stále jsem neslyšel nějak proč "je to nejhorší způsob". Opravdu nevidím důvod psát tunu kódu, jen kvůli tomu že chci Bindovat properties (nechci animace, nechci validaci,..), když mi postačí pár řádků a funguje to. DP se naučím a třeba uznám, že jsou výhodnější.

K samotnému problému. Jak jsem psal, už mi to funguje, jenom je ta validace nějaká pomalá cca 1-2 sec. jakoby aplikace zamrzne. Je to způsobené tedy to "nejhorší" možnou variantou a DP vše vyřeší (ačkoliv nechápu jak :) ) nebo je problém někde jinde ?

Díky za odpovědi, cením si jich :) A opravdu bych byl rád, kdyby jsi si našel chvíli a sepsal nějakou jednoduchou app, kde se bude bindovat a validovat jeden TextBox s použitím Dependency

Nahoru Odpovědět
13.12.2013 18:45
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
coells
Tvůrce
Avatar
Odpovídá na Petr Nymsa
coells:13.12.2013 18:54

Viz předchozí příspěvek: "nejhorší způsob, jak to napsat, protože je to tam kvůli zpětné kompatibilitě"

Zkoušel jsem si ráno ten tvůj příklad napsat za použití různých bindingů a validací a taky mi to "zamrzne", i když jen na desetinu sekundy. Když se podíváš do Output okna ve VS, uvidíš, že tam lítají výjimky z ConverterHelperu, myslím, že WPF se s tím neumí vyrovnat. Buď je problém interní výjimka v helperu nebo se tam hledá odpovídající šablona, což taky může trvat.

Když jsem místo toho použil vlastní ValidationRule, bylo to rychlé a bez zamrznutí. Takže řešení - vlastní ValidationRule místo explicitních výjimek.

 
Nahoru Odpovědět
13.12.2013 18:54
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na coells
Petr Nymsa:13.12.2013 19:05

Ještě jednou díky :) Musím se tedy pořádněji mrknout na ty DP a vlastně asi na spoustu dalších věcí.

Nahoru Odpovědět
13.12.2013 19:05
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
coells
Tvůrce
Avatar
coells:13.12.2013 19:07

Bývalý architekt WPF napsal knihu, mám ji doma také:

http://www.amazon.com/…S/ref=sr_1_2?…

 
Nahoru Odpovědět
13.12.2013 19:07
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na coells
Petr Nymsa:13.12.2013 19:23

Ještě se tedy chci se zeptat. ExceptionVali­dationRule vůbec nepoužívat ? Přitom mi přijde, že když vyvolám výjimku a toto pravidlo (by jej mělo) zachytí je "lepší" (resp. z hlediska množství kódu menší) než psát vlastní ValidationRule. Pro dnešek asi poslední otázka :)

//EDIT
Už jsi mě asi i přesvědčil. Pokud to tak chápu, když třída dědí z DependencyObject, stačí definovat DP a jednotlivé property. Jakákoliv změna v code-behind se automaticky zpropaguje do View ? -> tedy, že DependencyObject má něco jako INotifyProper­tyChanged ?

Editováno 13.12.2013 19:26
Nahoru Odpovědět
13.12.2013 19:23
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
coells
Tvůrce
Avatar
Odpovídá na Petr Nymsa
coells:13.12.2013 19:28

Ano, nepoužívat, viz http://msdn.microsoft.com/…P.40%29.aspx#…

Data Validation and Error Reporting
However, throwing exceptions with properties in this way should be avoided where possible. An alternative approach is to implement the IDataErrorInfo or INotifyDataErro­rInfo interfaces on your view model or model classes. These interfaces allow your view model or model to perform data validation for one or more property values and to return an error message to the view so that the user can be notified of the error.

 
Nahoru Odpovědět
13.12.2013 19:28
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na coells
Petr Nymsa:13.12.2013 19:31

Koukám že appky ve Windows 8 mají předgenerované pomocné třídy a ty DP vůbec nepoužívají, tj implmentují klasicky INotifyProper­tyChanged a klasické C# Properties 8|

Nahoru Odpovědět
13.12.2013 19:31
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
coells
Tvůrce
Avatar
Odpovídá na Petr Nymsa
coells:13.12.2013 19:36

OK, také mám jeden dotaz. V čem je tenhle zápis kratší než DP?

public class Questionnaire : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private string favoriteColor;

    public string FavoriteColor
    {
        get { return this.favoriteColor; }
        set
        {
            if (value != this.favoriteColor)
            {
                this.favoriteColor = value;
                if (this.PropertyChanged != null)
                {
                    this.PropertyChanged(this,
                          new PropertyChangedEventArgs("FavoriteColor"));
                }
            }
        }
    }
}
 
Nahoru Odpovědět
13.12.2013 19:36
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na coells
Petr Nymsa:13.12.2013 19:46

Abstraktní třída

abstract class BindableClass : INotifyPropertyChanged
   {

       protected void Set(string property)
       {
           if(PropertyChanged !=null)
               PropertyChanged(this,new PropertyChangedEventArgs(property))
       }
       public event PropertyChangedEventHandler PropertyChanged;
   }

Třída (viewModel)

class TestClass : BindableClass
   {

       private int foo;
       public int Foo { get { return foo; } set { foo = value; Set("Foo"); } }
   }

Nechci nijak zpochybňovat tvá tvrzení, napsal jsi mi nové poznatky, které se rád doučím. Několik diskuzí ohledně DP vs INotifyProper­tyChanged

http://stackoverflow.com/…pertychanged
http://stackoverflow.com/…in-viewmodel

Takže pokud nepotřebuju skrze XAML na tu vlastnost Bindovat (časté použití u vlastních controls, animace či styly) přijde mi lepší stále klasický přístup . Každopádně ještě určitě jednou díky, problém jak vyřešit jsi mi poradil a rozšířil jsi mi obzory :)

Nahoru Odpovědět
13.12.2013 19:46
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Jan Vargovský
Tvůrce
Avatar
Odpovídá na Petr Nymsa
Jan Vargovský:17.12.2013 21:50

Čtu tu knížku o WPFku a tady se píše, že vše co dědí z DependencyObject bys měl využívat DP(když to teda využiješ). Vždyť se to generuje pomocí code snippetu (propdp) pak párkrát vytabuješ a máš to hned :)

 
Nahoru Odpovědět
17.12.2013 21:50
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 38 zpráv z 38.