Pokazywanie postów oznaczonych etykietą dependency. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą dependency. Pokaż wszystkie posty

czwartek, 16 sierpnia 2012

[WPF] Attached Property

Attached Property to nic innego jak Dependency Property dołączane do obiektów już istniejących. Jest to na przykład świetny sposób na rozszerzanie kontrolek z których nie można dziedziczyć, lub z których dziedziczyć się nie opłaca, bo chcemy dodać tylko jedną prostą funkcjonalność. Przykładem AP jest Grid.Column ustawiane dla elementów potomnych. Ustawia się je w celu poinformowania rodzica o tym, jak mają być ustawione dzieci. Ogólnie założeniem AP jest, by klasy zgromadzone w pewien sposób w hierarchii lub powiązane w pewien logiczny sposób mogły zgłaszać wspólną informację do typu, które definiuje Attached Property. Typ ten może być zdefiniowany, jako rodzic, zawierający wiele dzieci. Iterując po nich może on wyciągać informacje, które go interesują. Inne zastosowanie, to serwis, który jest powiadamiany w momencie, gdy AttachedProperty jest ustawiane.

W poniższym przykładzie stworzono serwis, kontrolujący to, który prostokąt został wybrany. Attached Property rejestrowane jest podobnie jak Dependency Property specjalną metodą RegisterAttached.

<Window x:Class="Attached_Property.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Attached_Property="clr-namespace:Attached_Property" Title="MainWindow" Height="200" Width="200">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Rectangle Width="100" Height="100" MouseEnter="Rect3_MouseEnter"
                   x:Name="Rect1" Stroke="Red" Grid.Column="0" Grid.Row="0" 
                   Fill="LightGreen" Attached_Property:RectangleService.IsChecked="True" />
        <Rectangle Width="100" Height="100"  MouseEnter="Rect3_MouseEnter"
                   x:Name="Rect2" Stroke="Red" Grid.Column="1" Grid.Row="0" />
        <Rectangle Width="100" Height="100" MouseEnter="Rect3_MouseEnter"
                   x:Name="Rect3" Stroke="Red" Grid.Column="0" Grid.Row="1" />
        <Rectangle Width="100" Height="100" MouseEnter="Rect3_MouseEnter"
                   x:Name="Rect4" Stroke="Red" Grid.Column="1" Grid.Row="1" />
    </Grid>
</Window>


 public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Rect3_MouseEnter(object sender, MouseEventArgs e)
        {
            RectangleService.SetIsChecked(sender as DependencyObject, true);
        }
    }


 public class RectangleService
    {
        public static readonly DependencyProperty IsCheckedProperty;

        public static Rectangle CheckedRect { get; set; }

        static RectangleService()
        {
            IsCheckedProperty = DependencyProperty.RegisterAttached("IsChecked"
                              typeof (bool), typeof (Rectangle),
                                                new PropertyMetadata(false));
        }

        public static void SetIsChecked(DependencyObject element, bool value)
        {
            element.SetValue(RectangleService.IsCheckedProperty, value);
            //service logic
            if (!value) return;
            if(CheckedRect != null)
                CheckedRect.Fill = new SolidColorBrush(Colors.Yellow);
            CheckedRect = element as Rectangle;
            if(CheckedRect== null)
                return;
            CheckedRect.Fill = new SolidColorBrush(Colors.LightGreen);
        }

        public static bool GetIsChecked(DependencyObject element)
        {
            return (bool)element.GetValue(RectangleService.IsCheckedProperty);
        }

środa, 15 sierpnia 2012

[WPF] Dependency Property

Jedną z najważniejszych koncepcji w WPF jest Dependency Property. Umożliwiają one stylowanie, automatyczny data binding czy animowanie dowolnych właściwości. Dependency Property może być zmieniane przez wiele obiektów jednocześnie, a jego największą zaletą jest wbudowana zdolność do notyfikowania o zmianach wartości. DP mogą być także zmieniane z poziomu xaml co jest następną ich zaletą. Zatem przy tworzeniu własnych kontrolek jest to bardzo wygodne rozwiązanie. Kolejną korzyścią wynikającą z zastosowania DP jest możliwosć zdefiniowania Property Triggerów - warunkowych akcji wykonywanych, gdy property osiągnie pewną wartość

Od strony języka DP są propertiesami, budowanymi w dość nietypowy sposób. Należy dodać do klasy kontrolki statyczne publiczne pole tylko do odczytu, gdzie nazwa to nazwa property z dodanym "Property". Następnie w statycznym konstruktorze rejestruje się DP za pomocą metody DependencyProperty.Register. Przez parametry tej metody można określić domyślną wartość i metodę wołaną przy zmianie wartości. Można także zdefiniować pewien "wrapper", który będzie opakowywał ustawianie i odczyt wartości DP.

W poniższym przykładzie dla kontrolki tykającego zegarka zdefiniowano Dependency Property Ticks, które reprezentuje liczbę uderzeń zegarka.

 public partial class TickingTimer : UserControl
    {

        public static readonly DependencyProperty TicksProperty;

        public int Ticks
        {
            get { return (int)GetValue(TickingTimer.TicksProperty); }
            set { SetValue(TickingTimer.TicksProperty, value); }
        }

        static TickingTimer()
        {
            TickingTimer.TicksProperty = DependencyProperty.Register("Ticks",
                typeof(int), typeof(TickingTimer),
                new FrameworkPropertyMetadata(0,
                new PropertyChangedCallback(OnTicksChanged)));
        }

        private static void OnTicksChanged(DependencyObject o, DependencyPropertyChangedEventArgs eventArgs)
        {
            Console.Beep();
        }
//LOGIKA KONTROLKI
     }

Kontrolkę taką można dodać do okna i zbindować się do naszego Dependency Property Ticks.

<Window x:Class="Dependency_Property.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:Dependency_Property="clr-namespace:Dependency_Property" 
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Dependency_Property:TickingTimer x:Name="Timer" Ticks="5" />
        <Label Content="{Binding ElementName=Timer,  Path=Ticks}" />
    </Grid>
</Window>