Przejdź do treści stopki
Iron Academy Logo
Naucz się C#
Naucz się C#

Inne Kategorie

Zrozumienie zdarzeń w C#

Tim Corey
1h 9m 13s

Zdarzenia w C# są fundamentalnym pojęciem, które wielu programistów wykorzystuje, ale nie zawsze w pełni rozumie, zwłaszcza gdy chodzi o tworzenie własnych zdarzeń. Tim Corey przedstawia kompleksowy przewodnik dotyczący tworzenia i używania zdarzeń, omawiając najlepsze praktyki i zaawansowane funkcje w swoim wideo "C# Events - Creating and Consuming Events in Your Application".

W tym artykułe zamierzamy zgłębić zdarzenia w C#, koncentrując się na ich składni, jak są definiowane i jak pomagają rozwiązywać typowe problemy programistyczne korzystając z przykładów wideo Tima Coreya. Zrozumienie obsługi zdarzeń w C# jest niezbędne do budowania responsywnych aplikacji, a ten artykuł pomoże Ci uchwycić kluczowe pojęcia dotyczące niestandardowego logowania błędów, obsługi wyjątków i programowania zdarzeniowego.

Wprowadzenie do zdarzeń

W C# i językach programowania zdarzenia odgrywają kluczową rolę w programowaniu zdarzeniowym, umożliwiając aplikacjom reagowanie na działania, takie jak interakcje użytkowników lub zmiany systemówe. W porównaniu do innych języków programowania, C# oferuje strukturalne podejście do obsługi zdarzeń, co czyni go idealnym zarówno dla szybkich, jak i małych aplikacji. Zdarzenia w C# są wywoływane przez określone akcje, a te akcje wywołują odpowiednie obsługujące zdarzenia do wykonania pożądanych zadań.

Tim zaczyna wyjaśniając, że większość programistów zna zdarzenia w C#, ale może nie wiedzieć, jak tworzyć niestandardowe zdarzenia. Celem wideo jest wprowadzenie do zdarzeń, przejście przez tworzenie niestandardowych zdarzeń, omówienie ich funkcji i nakreślenie najlepszych praktyk.

Demonstracja aplikacji - przewodnik

Tim korzysta z prostej aplikacji bankowej zbudowanej w Windows Forms (WinForms) do zademonstrowania zdarzeń. Aplikacja symuluje podstawowe operacje bankowe dla jednego klienta, w tym wyświetlanie sald i rejestrowanie transakcji.

  1. Przegląd aplikacji:

    • Aplikacja ma dwa formularze: jeden do wyświetlania sald kont i transakcji, a drugi do rejestrowania nowych transakcji.
    • Zawiera przyciski do symulacji zakupów kartą kredytową i obsługi przekroczeń, przenosząc środki z oszczędności na bieżące konto.
  2. Główny formularz:

    • Wyświetla imię klienta, salda konta bieżącego i oszczędnościowego.
    • Pokazuje listy transakcji na obu kontach.
    • Zawiera przycisk do otwarcia formularza rejestrowania transakcji.
  3. Formularz transakcji:

    • Umożliwia użytkownikowi wprowadzanie kwot transakcji.
    • Symuluje dokonywanie zakupów i obsługuje przekroczenia, przenosząc środki z oszczędności na konto bieżące.

Kod za aplikacją demonstracyjną

Tim wyjaśnia kod zaplecza aplikacji bankowej demonstracyjnej:

  1. Klasa klienta:

    • Reprezentuje klienta z właściwościami na imię klienta i dwa konta (bieżące i oszczędnościowe).
    • Klasa klienta jest prosta, ale stanowi dobre wprowadzenie do zrozumieniuiuiuiuia, jak zarządzać wieloma kontami.
  2. Klasa konta:

    • Zarządza szczegółami konta bankowego, w tym nazwą konta, saldem i listą transakcji.
    • Właściwość Balance jest typu decimal dla precyzyjnych obliczeń pieniężnych.
    • Właściwość Transactions jest listą tylko do odczytu, aby zapobiec modyfikacjom z zewnątrz.
  3. Obsługa wpłat i płatności:

    • Metoda AddDeposit: Dodaje wpłatę do konta, aktualizuje saldo i rejestruje transakcję.
    • Metoda MakePayment: Obsługuje wypłaty, w tym sprawdzanie dostępności środków oraz zarządzanie ochroną przed przekroczeniem salda poprzez przelewanie środków z konta rezerwowego w razie potrzeby.
  4. Ochrona przed przekroczeniem salda:

    • Aplikacja zawiera logikę obsługi debetu. Jeśli saldo konta bieżącego jest niewystarczające do przeprowadzenia transakcji, aplikacja sprawdza konto oszczędnościowe w celu pokrycia niedoboru. Jeśli łączne saldo jest wystarczające, przelewa wymagańą kwotę na rachunek bieżący i finalizuje transakcję.

Jeśli chodzi o przykłady kodu, możesz od razu obejrzeć film Tima Coreya, w którym wyjaśnia on kod od 3:18 do 18:27.

Zdarzenie: Kliknięcie przycisku

W tej sekcji Tim Corey zagłębił się w działanie zdarzeń kliknięcia przycisku w Windows Forms, wyjaśniając, w jaki sposób zdarzenia te są połączone i jak funkcjonują.

Zrozumienie zdarzeń kliknięcia przycisku

Tim zaczyna od wyjaśnienia znanej koncepcji zdarzeń kliknięcia przycisku w aplikacjach Windows Forms. Po dwukrotnym kliknięciu przycisku w projektancie program Visual Studio automatycznie generuje metodę obsługi zdarzenia dla zdarzenia kliknięcia.

  1. Metoda obsługi zdarzeń:

    • Ta metoda jest wywoływana za każdym razem, gdy kliknięty zostanie przycisk. W tym miejscu umieszczasz kod, który powinien zostać uruchomiony w odpowiedzi na kliknięcie przycisku.
    private void recordTransactionButton_Click(object sender, EventArgs e)
    {
       // Code to handle the button click event
    }
    private void recordTransactionButton_Click(object sender, EventArgs e)
    {
       // Code to handle the button click event
    }
  2. Podłączanie zdarzenia:

    • Metoda obsługi zdarzeń jest powiązana ze zdarzeniem kliknięcia przycisku w pliku projektanta formularza (FormName.Designer.cs). Odbywa się to za pomocą operatora += w celu dodania procedury obsługi zdarzenia do zdarzenia kliknięcia przycisku.
    this.recordTransactionButton.Click += new System.EventHandler(this.recordTransactionButton_Click);
    this.recordTransactionButton.Click += new System.EventHandler(this.recordTransactionButton_Click);

Tworzenie i wywoływanie zdarzeń niestandardowych

Tim wyjaśnia, jak tworzyć niestandardowe zdarzenia w języku C#, zaczynając od klasy Account, w której będą wyzwalane zdarzenia.

  1. Definiowanie zdarzenia:

    • Zdarzenie definiuje się za pomocą słowa kluczowego event. Wygląda podobnie do zmiennej publicznej, ale jest przeznaczona specjalnie dla zdarzeń.
    public event EventHandler<string> RaiseTransactionApprovedEvent;
    public event EventHandler<string> RaiseTransactionApprovedEvent;
  2. Wywołanie zdarzenia:

    • Zdarzenia są wyzwalane za pomocą metody Invoke, zazwyczaj w klasie definiującej dane zdarzenie. Metoda Invoke przyjmuje dwa parametry: nadawcę (zazwyczaj this) i dane zdarzenia (w tym przypadku ciąg znaków).
    private void OnTransactionApproved(string transactionName)
    {
       RaiseTransactionApprovedEvent?.Invoke(this, transactionName);
    }
    private void OnTransactionApproved(string transactionName)
    {
       RaiseTransactionApprovedEvent?.Invoke(this, transactionName);
    }
  3. Podłączanie i obsługa zdarzeń:

    • Zarejestruj się na wydarzenie za pomocą operatora += i zdefiniuj metodę do obsługi zdarzenia, gdy zostanie ono wywołane.
    account.RaiseTransactionApprovedEvent += Account_RaiseTransactionApprovedEvent;
    
    private void Account_RaiseTransactionApprovedEvent(object sender, string e)
    {
       // Code to handle the event
    }
    account.RaiseTransactionApprovedEvent += Account_RaiseTransactionApprovedEvent;
    
    private void Account_RaiseTransactionApprovedEvent(object sender, string e)
    {
       // Code to handle the event
    }

Wykorzystanie zdarzeń do aktualizacji interfejsu użytkownika

Tim wyjaśnia, jak używać zdarzeń do automatycznej aktualizacji interfejsu użytkownika przeglądarki, gdy mają miejsce określone działania, takie jak zatwierdzenie transakcji.

  1. Generowanie zdarzeń:

    • Wywołaj zdarzenie niestandardowe po zatwierdzeniu transakcji.
    public void AddDeposit(decimal amount, string depositName)
    {
       // Code to add deposit
       RaiseTransactionApprovedEvent?.Invoke(this, depositName);
    }
    public void AddDeposit(decimal amount, string depositName)
    {
       // Code to add deposit
       RaiseTransactionApprovedEvent?.Invoke(this, depositName);
    }
  2. Subskrypcja zdarzeń w interfejsie użytkownika:

    • Zapisz się na wydarzenie w głównym formularzu, aby aktualizować listę transakcji za każdym razem, gdy nowa transakcja zostanie zatwierdzona.
    public MainForm()
    {
       InitializeComponent();
       account.RaiseTransactionApprovedEvent += Account_RaiseTransactionApprovedEvent;
    }
    
    private void Account_RaiseTransactionApprovedEvent(object sender, string e)
    {
       // Update the UI with the new transaction
    }
    public MainForm()
    {
       InitializeComponent();
       account.RaiseTransactionApprovedEvent += Account_RaiseTransactionApprovedEvent;
    }
    
    private void Account_RaiseTransactionApprovedEvent(object sender, string e)
    {
       // Update the UI with the new transaction
    }

Wyjaśnienie metody Event?.Invoke()

Tim Corey wyjaśnia użycie składni ?.Invoke() podczas generowania zdarzeń w języku C#. To nowoczesne podejście upraszcza kod i zapewnia bezpieczeństwo wątków.

Operator znaku zapytania

Znak zapytania (?) przed słowem Invoke oznacza operator warunkówy null. Sprawdza, czy procedurka obsługi zdarzenia ma wartość null przed jej wywołaniem, zapobiegając potencjalnym wyjątkom.

  1. Podejście tradycyjne:

    • Wcześniej programiści używali wielu wierszy kodu, aby sprawdzić, czy procedurka obsługi zdarzenia ma wartość null, a następnie ją wywołać.
    if (RaiseTransactionApprovedEvent != null)
    {
       RaiseTransactionApprovedEvent(this, depositName);
    }
    if (RaiseTransactionApprovedEvent != null)
    {
       RaiseTransactionApprovedEvent(this, depositName);
    }
  2. Nowoczesne podejście z ?.Invoke():

    • Operator warunkówy null usprawnia ten proces, wykonując sprawdzenie wartości null i wywołując zdarzenie w jednej linii.
    RaiseTransactionApprovedEvent?.Invoke(this, depositName);
    RaiseTransactionApprovedEvent?.Invoke(this, depositName);
    • Jeśli RaiseTransactionApprovedEvent jest nullem, wywołanie nie następuje, skutecznie unikając wyjątków.
  3. Zalety:

    • Upraszcza kod: zmniejsza ilość kodu potrzebnego do bezpiecznego wywoływania zdarzeń.
    • Bezpieczeństwo wątków: Eliminuje warunki wyścigu poprzez sprawdzanie wartości null i wywołanie zdarzenia w jednym kroku.

Słuchanie i pisanie kodu na wydarzeniu

Tim wyjaśnia, jak nasłuchiwać zdarzeń niestandardowych w aplikacji Windows Forms i odpowiednio aktualizować interfejs użytkownika.

  1. Subskrypcja wydarzeń:

    • Zarejestruj się do niestandardowego zdarzenia za pomocą operatora +=.
    customer.CheckingAccount.TransactionApprovedEvent += CheckingAccount_TransactionApprovedEvent;
    customer.CheckingAccount.TransactionApprovedEvent += CheckingAccount_TransactionApprovedEvent;
  2. Metoda obsługi zdarzeń:

    • Zdefiniuj metodę do obsługi zdarzenia. Ta metoda aktualizuje interfejs użytkownika na podstawie danych zdarzeń.
    private void CheckingAccount_TransactionApprovedEvent(object sender, string e)
    {
       // Update the UI with the new transaction
       checkingTransactionsDataSource.DataSource = null;
       checkingTransactionsDataSource.DataSource = customer.CheckingAccount.Transactions;
       checkingBalanceLabel.Text = customer.CheckingAccount.Balance.ToString("C2");
    }
    private void CheckingAccount_TransactionApprovedEvent(object sender, string e)
    {
       // Update the UI with the new transaction
       checkingTransactionsDataSource.DataSource = null;
       checkingTransactionsDataSource.DataSource = customer.CheckingAccount.Transactions;
       checkingBalanceLabel.Text = customer.CheckingAccount.Balance.ToString("C2");
    }

Tworzenie niestandardowego zdarzenia: zdarzenie w praktyce i podsumowanie

Tim demonstruje cały proces tworzenia, wywoływania i obsługi zdarzeń niestandardowych w praktyce.

  1. Wywołanie zdarzenia:

    • Wywołaj zdarzenie po zatwierdzeniu transakcji lub gdy zmieni się saldo.
    private void OnTransactionApproved(string transactionName)
    {
       RaiseTransactionApprovedEvent?.Invoke(this, transactionName);
    }
    private void OnTransactionApproved(string transactionName)
    {
       RaiseTransactionApprovedEvent?.Invoke(this, transactionName);
    }
  2. Obsługa wielu zdarzeń:

    • Upewnij się, że aplikacja nasłuchuje wielu zdarzeń, takich jak transakcje i zmiany salda, aby interfejs użytkownika był aktualizowany w czasie rzeczywistym.
    public MainForm()
    {
       InitializeComponent();
       customer.CheckingAccount.TransactionApprovedEvent += CheckingAccount_TransactionApprovedEvent;
       customer.SavingsAccount.TransactionApprovedEvent += SavingsAccount_TransactionApprovedEvent;
    }
    
    private void SavingsAccount_TransactionApprovedEvent(object sender, string e)
    {
       // Update the UI with the new savings transaction
       savingsTransactionsDataSource.DataSource = null;
       savingsTransactionsDataSource.DataSource = customer.SavingsAccount.Transactions;
       savingsBalanceLabel.Text = customer.SavingsAccount.Balance.ToString("C2");
    }
    public MainForm()
    {
       InitializeComponent();
       customer.CheckingAccount.TransactionApprovedEvent += CheckingAccount_TransactionApprovedEvent;
       customer.SavingsAccount.TransactionApprovedEvent += SavingsAccount_TransactionApprovedEvent;
    }
    
    private void SavingsAccount_TransactionApprovedEvent(object sender, string e)
    {
       // Update the UI with the new savings transaction
       savingsTransactionsDataSource.DataSource = null;
       savingsTransactionsDataSource.DataSource = customer.SavingsAccount.Transactions;
       savingsBalanceLabel.Text = customer.SavingsAccount.Balance.ToString("C2");
    }
  3. Uruchamianie aplikacji:

    • Tim uruchamia aplikację, aby zademonstrować, w jaki sposób interfejs użytkownika aktualizuje się automatycznie w oparciu o zdarzenia wywołane przez transakcje.

Informacje o argumentach zdarzeń: debugowanie

Tim pokazuje, jak debugować zdarzenia i sprawdzać informacje wysyłane wraz z nimi.

  1. Ustawianie punktu przerwania:

    • Ustaw punkt przerwania w metodzie obsługi zdarzeń, aby sprawdzić dane zdarzenia.
    private void CheckingAccount_TransactionApprovedEvent(object sender, string e)
    {
       // Breakpoint here
    }
    private void CheckingAccount_TransactionApprovedEvent(object sender, string e)
    {
       // Breakpoint here
    }
  2. Debugowanie:

    • Uruchom aplikację i wykonaj transakcję, aby wywołać zdarzenie. Sprawdź argumenty zdarzenia w debuggerze.
    • Parametr sender dostarcza instancję, która wywołała zdarzenie, a parametr e zawiera dane zdarzenia.

Tworzenie kolejnego zdarzenia niestandardowego (zdarzenie przekroczenia salda)

Tim Corey rozszerza demo, tworząc kolejne niestandardowe zdarzenie do obsługi sytuacji przekroczenia salda. Zdarzenie to zostanie wywołane w przypadku wystąpienia debetu i powiadomi użytkownika o kwocie debetu.

Definiowanie zdarzenia przekroczenia salda

Tim zaczyna od zdefiniowania nowego zdarzenia w klasie Account dla scenariuszy przekroczenia salda:

  1. Deklaracja zdarzenia:

    • Zdefiniuj zdarzenie przy użyciu słowa kluczowego event z typem dziesiętnym, aby przekazać kwotę debetu.
    public event EventHandler<decimal> OverdraftEvent;
    public event EventHandler<decimal> OverdraftEvent;
  2. Wywołanie zdarzenia:

    • Zdarzenie jest wyzwalane w tej części kodu, w której dochodzi do pomyślnego przekroczenia limitu.
    if (overdraftSuccessful)
    {
       OverdraftEvent?.Invoke(this, overdraftAmount);
    }
    if (overdraftSuccessful)
    {
       OverdraftEvent?.Invoke(this, overdraftAmount);
    }

Subskrypcja zdarzenia przekroczenia salda na stronie pulpitu nawigacyjnego

  1. Podłączanie zdarzenia:

    • Zapisz się do zdarzenia przekroczenia salda w formularzu Dashboard.
    customer.CheckingAccount.OverdraftEvent += CheckingAccount_OverdraftEvent;
    customer.CheckingAccount.OverdraftEvent += CheckingAccount_OverdraftEvent;
  2. Obsługa zdarzenia:

    • Zdefiniuj procedurę obsługi zdarzenia, aby wyświetlać komunikat w przypadku wystąpienia debetu.
    private void CheckingAccount_OverdraftEvent(object sender, decimal e)
    {
       errorMessage.Text = $"You had an overdraft protection transfer of {e:C2}";
       errorMessage.Visible = true;
    }
    private void CheckingAccount_OverdraftEvent(object sender, decimal e)
    {
       errorMessage.Text = $"You had an overdraft protection transfer of {e:C2}";
       errorMessage.Visible = true;
    }
  3. Wyzwalanie i wyświetlanie zdarzenia:

    • Gdy wystąpi przekroczenie limitu, zdarzenie uruchamia się i aktualizuje interfejs użytkownika, aby powiadomić użytkownika.
    You had an overdraft protection transfer of $20.44

Nasłuchiwanie zdarzenia w wielu miejscach

Tim wyjaśnia, jak nasłuchiwać tego samego zdarzenia w wielu językach i formach, demonstrując wszechstronność zdarzeń.

  1. Dodawanie etykiety do innego formularza:

    • Dodaj etykietę do formularza pomocniczego, aby wyświetlać komunikaty o przekroczeniu limitu.
    <asp:Label ID="errorMessage" runat="server" Visible="false" />
    <asp:Label ID="errorMessage" runat="server" Visible="false" />
    HTML
  2. Rejestracja na wydarzenie:

    • Zarejestruj się na wydarzenie dotyczące debetu w formularzu dodatkowym.
    customer.CheckingAccount.OverdraftEvent += SecondaryForm_OverdraftEvent;
    customer.CheckingAccount.OverdraftEvent += SecondaryForm_OverdraftEvent;
  3. Obsługa zdarzenia:

    • Zdefiniuj procedurę obsługi zdarzenia, aby wyświetlić komunikat o przekroczeniu limitu na formularzu pomocniczym.
    private void SecondaryForm_OverdraftEvent(object sender, decimal e)
    {
       errorMessage.Visible = true;
    }
    private void SecondaryForm_OverdraftEvent(object sender, decimal e)
    {
       errorMessage.Visible = true;
    }
  4. Obsługa zdarzeń równoczesnych:

    • Tim pokazuje, że zdarzenie może być obsługiwane w wielu formach jednocześnie, co gwarantuje, że wszystkie istotne części aplikacji odpowiednio na nie zareagują.
    Both the main form and the secondary form display the overdraft message when the event is triggered.

Usuwanie detektorów zdarzeń z pamięci

Tim podkreśla znaczenie czyszczenia detektorów zdarzeń w celu zapobiegania wyciekom pamięci i zapewnienia prawidłowej wydajności aplikacji.

  1. Rezygnacja ze zdarzeń:

    • Kluczowe jest rezygnowanie z subskrypcji zdarzeń przed zniszczeniem instancji klasy lub zamknięciem formularza.
    customer.CheckingAccount.OverdraftEvent -= CheckingAccount_OverdraftEvent;
    customer.CheckingAccount.OverdraftEvent -= CheckingAccount_OverdraftEvent;

    Dłączego to ważne:

    • Niezakończenie subskrypcji zdarzeń może powodować wycieki pamięci, ponieważ obiekty nasłuchujące zdarzeń mogą nie zostać prawidłowo zebrane przez garbage collector.
  2. Korzystanie z nazwanych metod:

    • Unikaj używania funkcji anonimowych dla obsługi zdarzeń, ponieważ trudno jest wtedy zrezygnować z subskrypcji zdarzeń.
    // Good practice: using named methods for event handlers
    // Good practice: using named methods for event handlers

Ogólny EventHandler: Przekazywanie klasy dla T

Tim Corey wyjaśnia najlepsze praktyki dotyczące przekazywania danych za pośrednictwem zdarzeń, szczególnie zalety używania klasy zamiast prostych typów danych, takich jak string czy decimal.

Dłączego używać klasy dla danych zdarzenia

Tim zaczyna, omawiając, dłączego używanie prostych typów danych dla zdarzeń jest mniej powszechne i dłączego lepiej jest zazwyczaj przekazywać klasę:

  1. Elastyczność i skalowalność:

    • Użycie klasy pozwala na przekazanie wielu powiązanych informacji przez zdarzenie. Jeśli później zajdzie potrzeba dodania większej ilości danych, można po prostu rozszerzyć klasę bez zmiany sygnatury zdarzenia.
  2. Dziedziczenie EventArgs:

    • Chociaż dawniej wymagańe było, aby każdy obiekt przekazywany przez zdarzenie dziedziczył z EventArgs, to obecnie nie jest to konieczne. Jednakże, dziedziczenie z EventArgs może być ciągle korzystne dla spójności i przejrzystości.

Tworzenie klasy Overdraft EventArgs

Tim demonstruje, jak stworzyć niestandardową klasę EventArgs dla zdarzenia niedopłaty.

  1. Zdefiniuj klasę:

    • Utwórz nową klasę dziedziczącą z EventArgs, zawierającą właściwości dla danych, które chcesz przekazać przez zdarzenie.
    public class OverdraftEventArgs : EventArgs
    {
       public decimal AmountOverdrafted { get; private set; }
       public string MoreInfo { get; private set; }
    
       public OverdraftEventArgs(decimal amountOverdrafted, string moreInfo)
       {
           AmountOverdrafted = amountOverdrafted;
           MoreInfo = moreInfo;
       }
    }
    public class OverdraftEventArgs : EventArgs
    {
       public decimal AmountOverdrafted { get; private set; }
       public string MoreInfo { get; private set; }
    
       public OverdraftEventArgs(decimal amountOverdrafted, string moreInfo)
       {
           AmountOverdrafted = amountOverdrafted;
           MoreInfo = moreInfo;
       }
    }
  2. Korzystanie z klasy w zdarzeniu:

    • Zaktualizuj deklarację zdarzenia, aby używać niestandardowej klasy EventArgs.
    public event EventHandler<OverdraftEventArgs> OverdraftEvent;
    public event EventHandler<OverdraftEventArgs> OverdraftEvent;
  3. Wywołanie zdarzenia:

    • Przekaż instancję niestandardowej klasy EventArgs przy wywołaniu zdarzenia.
    OverdraftEvent?.Invoke(this, new OverdraftEventArgs(amountNeeded, "Additional info"));
    OverdraftEvent?.Invoke(this, new OverdraftEventArgs(amountNeeded, "Additional info"));

Znaczenie właściwości tylko do odczytu

Tim podkreśla znaczenie używania właściwości tylko do odczytu w klasie EventArgs, aby zapobiec przypadkowej modyfikacji danych zdarzenia.

  1. Unikanie modyfikacji:

    • Jeśli właściwości w klasie EventArgs mają publiczne settery, każdy obsługujący zdarzenie może modyfikować dane, co może prowadzić do nieoczekiwanego zachowania.
    • Użycie prywatnych setterów oraz inicjowanie właściwości przez konstruktor zapewnia, że dane zdarzenia pozostają spójne.
  2. Przykład problemu:

    • Tim pokazuje, jak modyfikacja danych zdarzenia w jednym obsługującym zdarzenie może wpłynąć na inne obsługujące, jeśli właściwości nie są tylko do odczytu.
    private void CheckingAccount_OverdraftEvent(object sender, OverdraftEventArgs e)
    {
       e.AmountOverdrafted = 1000; // This modification affects all handlers
    }
    private void CheckingAccount_OverdraftEvent(object sender, OverdraftEventArgs e)
    {
       e.AmountOverdrafted = 1000; // This modification affects all handlers
    }
  3. Rozwiązanie:

    • Użyj prywatnych setterów i przekazuj dane przez konstruktor, aby właściwości były tylko do odczytu.
    public decimal AmountOverdrafted { get; private set; }
    public string MoreInfo { get; private set; }
    public decimal AmountOverdrafted { get; private set; }
    public string MoreInfo { get; private set; }

Wyjątek, kiedy używać publicznego setera

Tim Corey podkreśla ważny wyjątek od zasady używania prywatnych setterów dla właściwości danych zdarzenia. Ten wyjątek dotyczy sytuacji, gdy konieczne jest umożliwienie słuchaczom zdarzenia modyfikacji danych zdarzenia, na przykład w przypadkach, gdy transakcja może zostać anulowana na podstawie określonych warunków.

Przykład: Anulowanie transakcji

Tim przedstawia przykład, w którym obsługujący zdarzenie może potrzebować anulować transakcję. Osiąga się to przez dodanie właściwości CancelTransaction do niestandardowej klasy EventArgs.

  1. Definiowanie właściwości:

    • Dodaj publiczną właściwość z getterem i seterem do klasy EventArgs.
    public class OverdraftEventArgs : EventArgs
    {
       public decimal AmountOverdrafted { get; private set; }
       public string MoreInfo { get; private set; }
       public bool CancelTransaction { get; set; } = false;
    
       public OverdraftEventArgs(decimal amountOverdrafted, string moreInfo)
       {
           AmountOverdrafted = amountOverdrafted;
           MoreInfo = moreInfo;
       }
    }
    public class OverdraftEventArgs : EventArgs
    {
       public decimal AmountOverdrafted { get; private set; }
       public string MoreInfo { get; private set; }
       public bool CancelTransaction { get; set; } = false;
    
       public OverdraftEventArgs(decimal amountOverdrafted, string moreInfo)
       {
           AmountOverdrafted = amountOverdrafted;
           MoreInfo = moreInfo;
       }
    }
  2. Ustawienie właściwości w obsługującym zdarzenie:

    • Na pulpicie, obsługujący zdarzenie może ustawić tę właściwość w celu anulowania transakcji.
    private void CheckingAccount_OverdraftEvent(object sender, OverdraftEventArgs e)
    {
       if (denyOverdraft.Checked)
       {
           e.CancelTransaction = true;
       }
       errorMessage.Text = $"You had an overdraft protection transfer of {e.AmountOverdrafted:C2}";
       errorMessage.Visible = true;
    }
    private void CheckingAccount_OverdraftEvent(object sender, OverdraftEventArgs e)
    {
       if (denyOverdraft.Checked)
       {
           e.CancelTransaction = true;
       }
       errorMessage.Text = $"You had an overdraft protection transfer of {e.AmountOverdrafted:C2}";
       errorMessage.Visible = true;
    }
  3. Sprawdzanie właściwości w metodzie źródłowej:

    • W metodzie, która wywołuje zdarzenie, sprawdź, czy właściwość CancelTransaction jest ustawiona na true przed kontynuowaniem.
    if (args.CancelTransaction)
    {
       return false; // Transaction is canceled
    }
    if (args.CancelTransaction)
    {
       return false; // Transaction is canceled
    }

Uczynienie aplikacji bardziej interaktywną

Tim dalej udoskonala aplikację, aby była bardziej interaktywna i przyjazna dla użytkownika.

  1. Dodanie pola wyboru dla kontroli przekroczenia:

    • Dodaj pole wyboru do formularza, które umożliwia użytkownikowi włączenie lub wyłączenie zabezpieczenia przed przekroczeniami.
    private void InitializeComponent()
    {
       this.denyOverdraft = new System.Windows.Forms.CheckBox();
       // Initialize other controls
       this.denyOverdraft.Text = "Stop Overdrafts";
       this.denyOverdraft.CheckedChanged += new System.EventHandler(this.denyOverdraft_CheckedChanged);
    }
    private void InitializeComponent()
    {
       this.denyOverdraft = new System.Windows.Forms.CheckBox();
       // Initialize other controls
       this.denyOverdraft.Text = "Stop Overdrafts";
       this.denyOverdraft.CheckedChanged += new System.EventHandler(this.denyOverdraft_CheckedChanged);
    }
  2. Obsługa stanu pola wyboru:

    • W obsługującym zdarzenie dla pola wyboru, zaktualizuj logikę, aby uwzględniała stan pola wyboru przy podejmowaniu decyzji o anulowaniu transakcji.
    private void denyOverdraft_CheckedChanged(object sender, EventArgs e)
    {
       if (denyOverdraft.Checked)
       {
           // Logic to stop overdraft transactions
       }
    }
    private void denyOverdraft_CheckedChanged(object sender, EventArgs e)
    {
       if (denyOverdraft.Checked)
       {
           // Logic to stop overdraft transactions
       }
    }
  3. Aktualizacja obsługującego zdarzenie:

    • Upewnij się, że obsługujący zdarzenie respektuje stan pola wyboru, aby zezwalać lub odmawiać przekroczeń.
    private void CheckingAccount_OverdraftEvent(object sender, OverdraftEventArgs e)
    {
       if (denyOverdraft.Checked)
       {
           e.CancelTransaction = true;
       }
       errorMessage.Text = $"You had an overdraft protection transfer of {e.AmountOverdrafted:C2}";
       errorMessage.Visible = true;
    }
    private void CheckingAccount_OverdraftEvent(object sender, OverdraftEventArgs e)
    {
       if (denyOverdraft.Checked)
       {
           e.CancelTransaction = true;
       }
       errorMessage.Text = $"You had an overdraft protection transfer of {e.AmountOverdrafted:C2}";
       errorMessage.Visible = true;
    }

Podsumowanie

Tim Corey podsumowuje tutorial, omawiając kluczowe punkty i najlepsze praktyki dotyczące pracy ze zdarzeniami w C#.

  1. Usuń słuchaczy zdarzeń:

    • Zawsze usuwaj słuchaczy zdarzeń przed zniszczeniem obiektów, aby zapobiec wyciekom pamięci.
    • Użyj operatora -=, aby zrezygnować z subskrypcji zdarzeń.
    customer.CheckingAccount.OverdraftEvent -= CheckingAccount_OverdraftEvent;
    customer.CheckingAccount.OverdraftEvent -= CheckingAccount_OverdraftEvent;
  2. Użyj dziedziczenia EventArgs :

    • Chociaż nie jest to obowiązkowe, dziedziczenie z EventArgs może być korzystne dla spójności i korzystania z wbudowanych funkcji, takich jak EventArgs.Empty.
  3. Prywatne settery dla właściwości tylko do odczytu:

    • Użyj prywatnych setterów, aby zapobiec niezamierzonym modyfikacjom danych zdarzenia. Pozwól na publiczne settery tylko wtedy, gdy jest to konieczne, na przykład dla anulowalnych transakcji.
  4. Składnia obsługującego zdarzenie:

    • Użyj delegata EventHandler, aby definiować zdarzenia, zapewniając jasny i spójny wzorzec przekazywania danych zdarzenia.
  5. Operator warunkówy null:

    • Użyj operatora warunkówego null (?.Invoke()), aby bezpiecznie wywoływać zdarzenia bez ryzyka wyjątków odniesienia null.

Wnioski

Kompleksowy tutorial Tima Coreya o zdarzeniach C# zapewnia wartościowe spostrzeżenia i praktyczne przykłady dotyczące tworzenia, obsługi i zarządzania zdarzeniami efektywnie. Podążając za tymi najlepszymi praktykami, programiści mogą tworzyć bardziej interaktywne i responsywne aplikacje.

Hero Worlddot related to Zrozumienie zdarzeń w C#
Hero Affiliate related to Zrozumienie zdarzeń w C#

Zarabiaj więcej, dzieląc się tym, co kochasz

Tworzysz treści dla deweloperów pracujących z .NET, C#, Java, Python, czy Node.js? Zamień swoją wiedzę specjalistyczną na dodatkowy dochód!

Zespol wsparcia Iron

Jestesmy online 24 godziny, 5 dni w tygodniu.
Czat
Email
Zadzwon do mnie