"Head First" i INotifyPropertyChanged - można prościej?

1

Czytam "Head First". Znalazłem tam:

public event PropertyChangedEventHandler PropertyChanged;

// ...

private void OnPropertyChanged(string propertyName) {
    PropertyChangedEventHandler propertyChangedEvent = PropertyChanged;
    if (propertyChangedEvent != null) {
        propertyChangedEvent(this, new PropertyChangedEventArgs(propertyName));
    }
}

Dlaczego tak? Ja bym zrobił to tak:

public event PropertyChangedEventHandler PropertyChanged;

// ...

private void OnPropertyChanged(string propertyName) {
    if (PropertyChanged != null) {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

Dla mnie jest to to samo w działaniu, ale prościej. Nie mam racji? Może jeszcze czegoś nie wiem?

1

Naturalnie masz rację. Co więcej: da się to zrobić jeszcze krócej:

    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string property)
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
        }
    }

Każda klasa, która dziedziczy po ViewModelBase będzie miała z automatu dostępną metodę OnPropertyChanged.

0

Dzięki za odpowiedź. Pytałem, bo autorzy nawet napisali This is a standard .NET pattern for raising events. No i zdziwił mnie taki standard.

grzesiek51114 napisał(a):

Naturalnie masz rację. Co więcej: da się to zrobić jeszcze krócej:

Dzięki i za to. Ja już zastanawiałem się, czy tą podpowiedź IDE stosować, czy nie - bo nie zawsze te podpowiedzi są tym, co naprawdę chcemy zrobić. Teraz wiem, że tak.

Każda klasa, która dziedziczy po ViewModelBase będzie miała z automatu dostępną metodę OnPropertyChanged.

Ech, chodzenie po dziedziczeniu to jeszcze chyba nie dla mnie. Tu to mam tylko nadzieję, że IDE zażąda dodania override, co mi podpowie, że dziedziczę. Ale dobrze wiedzieć, że jest klasa ViewModelBase mająca OnPropertyChanged. Jeszcze raz dzięki.

2

Polecam skusić się na to dziedziczonko nawet bez jako takiej znajomości. Zaoszczędzi Ci to kopiowania kodu do każdej klasy, która będzie musiała implementować INotifyPropertyChanged. Naprawdę warto. ;)

Ale dobrze wiedzieć, że jest klasa ViewModelBase mająca OnPropertyChanged.

Nie no, takiej klasy nie ma. Trzeba ją sobie napisać, np. tak jak Ci pokazałem, o. ;)

0

Dzięki jeszcze raz. Bo już się bałem, że gdzieś w .NET jest taka klasa. I że jest klasa, nazwijmy ją A_1, która dziedziczy po niej. I jest klasa, nazwijmy ją A_2, dziedzicząca po A_1. I tak dalej.
I siadam do pisania. I tworzę klasę dziedziczącą po jakiejś A_n :-(. A tak poza tym to dziedziczenie w zasadzie nie jest dla problemem. No może jest w C#, bo przecież, trzeba wiedzieć, po czym dziedziczymy. A tu słaby jestem.
Ale może a propos dziedziczenia jeszcze jedno pytanie. Używam vs2015. A w "Head First" opowiadają o debugowaniu i jest obrazek:

screenshot-20170420140326.png

a u mnie tego base nie ma. I nawet nie wiem, o co wujka pytać.

0

@grzesiek51114 napisał:

Popatrz na komentarz, który napisał Ci @Ktos

no a @Ktos napisał:

Jest dostępna tylko, o ile używasz np. jakichś frameworków do MVVM; zazwyczaj ją ktoś już wtedy zrobił, a jak nie, to napisanie samemu to żaden problem.

Nie rozumiem. Nie używam frameworków. Przynajmniej nic o tym nie wiem. Oczywiście, że napisanie takiej klasy samemu, to żaden problem. I szkoda, że nie można dziedziczyć z dwóch klas. Ale pewnie dziedziczenie z takiej jednej też mi się przyda. Kiedyś :-).

Ale boję się, że wkrada się jakieś nieporozumienie. Dla mnie sprawa implementacji interfejsu INotifyPropertyChanged jest zamknięta.

Ale przy okazji dziedziczenia @grzesiek51114 zachęcał, żeby nie obawiać się. Nie obawiam się. Programuję obiektowo już 20 lat. A teraz przyszedł czas na c#. W chwilach wolnych.

W Head First, w rozdziale 2, jest taka prostacka aplikacja WPF. Z początku to nawet jej nie robiłem. Za łatwa. Ale w rozdziale 10 wspomnieli, jak można (debugging) obejrzeć, z czego coś dziedziczy. Przykład został nazwany PractiseUsingIfElse.

W zacytowanym (aby uniknąć nieporozumień) poniżej kodzie zaznaczyłem, gdzie zalecają ustawić breakpoint. To mój jedyny dopisek.

MainWindow.xaml :

<Window x:Name="mainWindow" x:Class="UsingIfElse.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:UsingIfElse"
        mc:Ignorable="d"
        Title="Fun with if / else statements." Height="150" Width="450" WindowStartupLocation="CenterOwner">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Button x:Name="changeText" Content="Change the label if checked" HorizontalAlignment="Center" VerticalAlignment="Center" Click="changeText_Click"/>
        <CheckBox x:Name="enableCheckbox" Content="Enable label changing" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center"/>
        <TextBlock x:Name="labelToChange" Grid.Row="1" TextWrapping="Wrap" Text="Press the button to set my text" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center"/>

    </Grid>
</Window>

MainWindow.xaml.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace UsingIfElse
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();                // <----- tu wstawiamy breakpoint
        }

        private void changeText_Click(object sender, RoutedEventArgs e)
        {
            if (enableCheckbox.IsChecked != true)
            {
                labelToChange.Text = "Text changing is disabled";
                labelToChange.HorizontalAlignment = HorizontalAlignment.Center;
            } else
            {
                if (labelToChange.Text == "Left")
                {
                    labelToChange.Text = "Right";
                    labelToChange.HorizontalAlignment = HorizontalAlignment.Right;
                } else
                {
                    labelToChange.Text = "Left";
                    labelToChange.HorizontalAlignment = HorizontalAlignment.Left;
                }
            }
        }
    }
}

I sprawdziłem, że w vs2010 uzyskujemy takie drzewko z base, jak na wcześniej załączonym obrazku. Czyli w vs2010 umiem zobaczyć, z czego dziedziczę. Ale w vs2015 (na tej samej maszynie) mam:
screenshot-20170420211756.png

I nie ma base. Przynajmniej na pierwszym poziomie drzewka. A przejrzałem całą listę. No to w c#, w vs2015 mam kłopot z dziedziczeniem. Jak na razie jedyny mi znany. Pewnie kiedyś się wyjaśni.

0

Nie zobaczysz tego ale w sumie nie jest to za bardzo potrzebne. I tak wszystkie dziedziczone rzeczy są pokazywane w debugu.

Zobacz tutaj. Postaw trapa w mainie, każ debuggerowi zrobić następny krok to będziesz widział własność z base'a.

    abstract class Base
    {
        public string Name { get; set; }
        public Base()
        {
            this.Name = "Some class";
        }
    }

    class FirstDerived : Base { }
    class SecondDerived : FirstDerived { }

    class Program
    {
        static void Main(string[] args)
        {
            Base some = new SecondDerived();
        }
    }
0

Najwyraźniej taka opcja zniknęła pomiędzy VS2010 i VS2015.

Ale ogólnie jest jeszcze takie narzędzie jak Object Browser, gdzie możesz sobie zobaczyć klasy i co z czego dziedziczy.

0
Ktos napisał(a):

Najwyraźniej taka opcja zniknęła pomiędzy VS2010 i VS2015.

Nie zniknęła. Znalazłem. Hura! Hura! Hura! Odpowiednik base nazywa się DependencyObjectType.
Ale dzięki za przypomnienie o Object Browser. Już zapomniałem, a po dziedziczeniu chodzi mi się tam wygodniej niż wykorzystując przechodzenie do definicji nadrzędnej (czyli pull down menu - Go To Definition F12).

1 użytkowników online, w tym zalogowanych: 0, gości: 1