[C# WPF] Readonly DependecyProperty

C++, C#, Visual Basic, Delphi, Perl a ostatní

Moderátor: Moderátoři Živě.cz

Odeslat příspěvekod BEZY 27. 8. 2011 14:34

Zdravím, snažím se dosáhnout následujícího:

Potřebuji vlastní třídu, která bude obsahovat následující properties: Count, Value, Amount. Platí vzorec
Kód: Vybrat vše
Amount = Count * Value


Abych mohl využít Binding, deklaroval jsem si je všechny jako DependencyProperty. Problém ale mám s Amount - chci, aby byla pouze readonly (použiji na ni pouze OneWay Binding) a její hodnota se měnila podle toho, jak nastavuji Count a Value. Toho se mi ale nijak nedaří docílit - vím jak nastavit callback pro Count a Value, ale už nevím, jak přinutit Amount, aby se znovu vyhodnotila - a projevil se tak daný OneWay Binding. Zkoušel jsem něco takového :

Kód: Vybrat vše
        public static readonly DependencyProperty UnitsProperty = DependencyProperty.Register("Units", typeof(double), typeof(AmountGridRow), new PropertyMetadata(OnAmountChangedCallBack));
        public double Units
        {
            get { return (double)GetValue(UnitsProperty); }
            set { SetValue(UnitsProperty, value); }
        }

        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(int), typeof(AmountGridRow), new PropertyMetadata(OnAmountChangedCallBack));
        public int Value
        {
            get { return (int)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        static void OnAmountChangedCallBack(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
             obj.InvalidateProperty(AmountProperty);
        }

        public static readonly DependencyPropertyKey AmountProperty = DependencyProperty.RegisterReadOnly("Amount", typeof(double), typeof(AmountGridRow), new PropertyMetadata(0));
        public double Amount
        {
            get { return (double)((double)GetValue(UnitsProperty) * (int)GetValue(ValueProperty)); }
            set { throw new Exception("An attempt to modify Read-Only property"); }
        }


(své naděje jsem sázel právě na obj.InvalidateProperty(AmountProperty); ale bez výsledku)

Samozřejmě se na svůj readonly požadavek můžu vykašlat, ale to by pak šlo Amount nastavit a rozhodilo by to zmíněný vzoreček...

Díky za nápovědu :)
BEZY
Junior
Uživatelský avatar

Odeslat příspěvekod Xenik 27. 8. 2011 14:39

Zkus mrknout na INotifyPropertyChanged a použít normální property.

edit: Jsem línej tu cokoliv vymýšlet, ale zkus mrknout sem http://msdn.microsoft.com/en-us/library/ms229614.aspx.

edit: V setteru Count a Value zavoláš NotifyPropertyChanged("Amount")
Xenik
Junior

Odeslat příspěvekod Falhar 27. 8. 2011 15:22

Jde o to, že DependencyProperty obecně obchází standardní property. Normální property s GetValue a SetValue jsou jen od toho, aby se daly DependencyProperty měnit z kódu. Takže logicky tvůj výpočet v getteru Amount se při bindingu vůbec nezavolá.

Rychlé googlení ( http://www.google.cz/search?q=calculate ... cyProperty ) vyhodilo :
http://social.msdn.microsoft.com/Forums ... 4525341bea
http://stackoverflow.com/questions/1364 ... on-another


Taky bych oponoval použití INotifyPropertyChanged, hlavně pokud se bude jednat o vlastní Control. Tam bych určitě použil DependencyProperty.

Taky mě napadlo, že by bylo dobré se podívat na ReadOnly DependencyProperty:
http://msdn.microsoft.com/en-us/library/ms754044.aspx
Falhar
Junior

Odeslat příspěvekod Xenik 27. 8. 2011 15:27

Můžu se optat proč se vyhnout INotifyPropertyChanged? DependencyProperty používám, pokud na tom místě chci bindovat na nějaká jiná data. Viz diskuse zde http://stackoverflow.com/questions/291518/inotifypropertychanged-vs-dependencyproperty-in-viewmodel.

Snažím se nepoužívat DP, kde to není nutné.
Xenik
Junior

Odeslat příspěvekod Falhar 27. 8. 2011 15:38

Protože DP byly vytvořeny pro nároky WPF na binding. Např. jedna strana bindingu ve WPF musí vždy být DP. Pokud tedy dělá vlastní Control, tak je použití DP klíčové.

INPC je naopak vhodné na druhé straně bindingu, ted většinou ve ViewModelu. Tam je zase použití DP "kanón na vrabce" a zbytečně způsobuje závislost na DependencyObject třídě a tím zhoršuje podmínky objektového návrhu.
Falhar
Junior

Odeslat příspěvekod Xenik 27. 8. 2011 15:43

Máte pravdu, takhle podáno s vámí souhlasím :-)
Xenik
Junior

Odeslat příspěvekod BEZY 27. 8. 2011 16:51

Ano, skutečně jsem to potřeboval ve vlastním Controlu, DP proto pro mě byla celkem jasná volba :)

Falhar>díky za tip, už jsem na to předtím narazil, ale nepochopil jsem použití klíče. Teď tomu snad rozumím - na venek se daná property tváří a chová jako read-only, ale pokud ji chci aktualizovat, tak použiji právě klíč získaný z RegisterReadOnly, který mám jako private.

Takže jsem se dostal do následujícího stavu:
Kód: Vybrat vše
public static readonly DependencyProperty UnitsProperty = DependencyProperty.Register("Units", typeof(double), typeof(AmountGridRow), new PropertyMetadata(OnAmountChangedCallBack));
        public double Units
        {
            get { return (double)GetValue(UnitsProperty); }
            set { SetValue(UnitsProperty, value); }
        }

        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(int), typeof(AmountGridRow), new PropertyMetadata(OnAmountChangedCallBack));
        public int Value
        {
            get { return (int)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        static void OnAmountChangedCallBack(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            AmountGridRow row = (AmountGridRow)obj;
            obj.SetValue(AmountKey, row.Units * row.Value);
        }

        private static readonly DependencyPropertyKey AmountKey = DependencyProperty.RegisterReadOnly("Amount", typeof(double), typeof(AmountGridRow), new PropertyMetadata(0.0));
        public static readonly DependencyProperty AmountProperty = AmountKey.DependencyProperty;
        public double Amount
        {
            get { return (double)GetValue(AmountProperty); }           
        }


A vše funguje :) Díky za rady
BEZY
Junior
Uživatelský avatar


Kdo je online

Uživatelé procházející toto fórum: Žádní registrovaní uživatelé a 0 návštevníků