Udostępnij za pośrednictwem


Badanie zdarzeń powiązanych ze wstawianiem, aktualizowaniem i usuwaniem (C#)

Autor: Scott Mitchell

Pobierz plik PDF

W tym samouczku przeanalizujemy użycie zdarzeń występujących przed, podczas i po operacji wstawiania, aktualizowania lub usuwania kontrolki danych ASP.NET w sieci Web. Zobaczymy również, jak dostosować interfejs edycji, aby zaktualizować tylko podzestaw pól produktu.

Wprowadzenie

W przypadku korzystania z wbudowanych funkcjonalności wstawiania, edytowania lub usuwania w kontrolkach GridView, DetailsView lub FormView, po ukończeniu przez użytkownika końcowego procesu dodawania nowego rekordu, aktualizacji lub usunięcia istniejącego rekordu, następują różne kroki. Jak opisano w poprzednim samouczku, gdy wiersz jest edytowany w GridView, przycisk Edytuj jest zastępowany przez przyciski Aktualizuj i Anuluj, a BoundFields zamieniają się w pola tekstowe. Po zaktualizowaniu danych przez użytkownika końcowego i kliknięciu przycisku Aktualizuj, w wyniku ponownego przesłania wykonywane są następujące kroki:

  1. Obiekt GridView wypełnia obiekty ObjectDataSource UpdateParameters unikatowymi polami identyfikacji edytowanego rekordu (za pośrednictwem DataKeyNames właściwości) oraz wartościami wprowadzonymi przez użytkownika
  2. Obiekt GridView wywołuje metodę Update() obiektu ObjectDataSource, która z kolei wywołuje odpowiednią metodę w obiekcie bazowym (ProductsDAL.UpdateProduct w poprzednim samouczku).
  3. Dane bazowe, które zawierają teraz zaktualizowane zmiany, są przywracane do kontrolki GridView

Podczas tej sekwencji kroków uruchamiana jest wiele zdarzeń, co umożliwia tworzenie procedur obsługi zdarzeń w celu dodania niestandardowej logiki tam, gdzie jest to konieczne. Na przykład przed krokiem 1 zdarzenie GridView RowUpdating jest uruchamiane. W tym momencie możemy anulować żądanie aktualizacji, jeśli wystąpił błąd weryfikacji. Po wywołaniu Update() metody zdarzenie ObjectDataSource Updating jest wyzwalane, co daje możliwość dodania lub dostosowania wartości dowolnego elementu UpdateParameters. Po zakończeniu wykonywania metody obiektu bazowego ObjectDataSource, zdarzenie Updated ObjectDataSource zostaje zgłoszone. Procedura obsługi zdarzeń dla Updated może sprawdzić szczegóły operacji aktualizacji, takie jak liczba zmienionych wierszy i czy doszło do wyjątku. Na koniec, po kroku 2, zdarzenie GridView RowUpdated jest wywoływane; program obsługi tego zdarzenia może zbadać dodatkowe informacje o właśnie wykonanej operacji aktualizacji.

Rysunek 1 przedstawia tę serię zdarzeń i kroków podczas aktualizowania kontrolki GridView. Wzorzec zdarzenia na rysunku 1 nie jest unikatowy do aktualizowania za pomocą kontrolki GridView. Wstawianie, aktualizowanie lub usuwanie danych z kontrolki GridView, DetailsView lub FormView powoduje utworzenie tej samej sekwencji zdarzeń wstępnych i po poziomie zarówno dla kontrolki sieci Web danych, jak i obiektu ObjectDataSource.

Seria zdarzeń przed i po zakończeniu uruchamia się podczas aktualizacji danych w GridView

Rysunek 1: Seria zdarzeń przed i po aktualizacji danych w GridView (kliknij, aby wyświetlić pełnowymiarowy obraz)

W tym samouczku przeanalizujemy, jak za pomocą tych zdarzeń rozszerzyć wbudowane funkcje wstawiania, aktualizowania i usuwania w kontrolkach danych ASP.NET. Zobaczymy również, jak dostosować interfejs edycji, aby zaktualizować tylko podzestaw pól produktu.

Krok 1: Aktualizowanie produktu i pólProductNameUnitPrice

W interfejsach edycji z poprzedniego samouczka wszystkie pola produktu, które nie były tylko do odczytu, musiały zostać uwzględnione. Gdybyśmy usunęli pole z kontrolki GridView — powiedzmy QuantityPerUnit — podczas aktualizowania danych kontrolka internetowa danych nie ustawiłaby wartości ObjectDataSource QuantityPerUnitUpdateParameters . Następnie, obiekt ObjectDataSource przekaże wartość null w metodzie warstwy logiki biznesowej (BLL), co spowoduje, że kolumna QuantityPerUnit edytowanego rekordu bazy danych zostanie zmieniona na wartość NULL. Podobnie, jeśli wymagane pole, takie jak ProductName, zostanie usunięte z interfejsu edycji, aktualizacja zakończy się niepowodzeniem z wyjątkiem "Kolumna "ProductName" nie zezwala na wartości null. Przyczyną tego zachowania było to, że obiekt ObjectDataSource został skonfigurowany do wywołania ProductsBLL metody klasy UpdateProduct , która oczekiwała parametru wejściowego dla każdego pola produktu. W związku z tym kolekcja ObjectDataSource UpdateParameters zawierała parametr dla każdego z parametrów wejściowych metody.

Jeśli chcemy podać kontrolkę sieci Web danych, która umożliwia użytkownikowi końcowemu aktualizowanie tylko podzestawu pól, musimy programowo ustawić brakujące UpdateParameters wartości w procedurze obsługi zdarzeń obiektu ObjectDataSource Updating lub utworzyć i wywołać metodę BLL, która oczekuje tylko podzestawu pól. Przyjrzyjmy się temu drugiemu podejściu.

W szczególności utwórzmy stronę, która wyświetla tylko pola ProductName i UnitPrice w edytowalnym widoku siatki. Interfejs edycji kontrolki GridView umożliwi użytkownikowi zaktualizowanie tylko dwóch wyświetlanych pól: ProductName i UnitPrice. Ponieważ ten interfejs edycji zapewnia tylko podzbiór pól produktu, musimy utworzyć nowy ObjectDataSource, który używa istniejącej metody BLL UpdateProduct i ma brakujące wartości pól produktu ustawione programowo w procedurze obsługi zdarzeń Updating, lub musimy utworzyć nową metodę BLL, która oczekuje tylko podzbioru pól zdefiniowanych w GridView. W tym samouczku użyjemy tej drugiej opcji i utworzymy przeciążenie tej metody UpdateProduct, które przyjmuje tylko trzy parametry wejściowe: productName, unitPrice i productID:

[System.ComponentModel.DataObjectMethodAttribute
    (System.ComponentModel.DataObjectMethodType.Update, false)]
public bool UpdateProduct(string productName, decimal? unitPrice, int productID)
{
    Northwind.ProductsDataTable products = Adapter.GetProductByProductID(productID);
    if (products.Count == 0)
        // no matching record found, return false
        return false;

    Northwind.ProductsRow product = products[0];

    product.ProductName = productName;
    if (unitPrice == null) product.SetUnitPriceNull();
      else product.UnitPrice = unitPrice.Value;

    // Update the product record
    int rowsAffected = Adapter.Update(product);

    // Return true if precisely one row was updated, otherwise false
    return rowsAffected == 1;
}

Podobnie jak w przypadku oryginalnej UpdateProduct metody, to przeciążenie rozpoczyna się od sprawdzenia, czy w bazie danych znajduje się produkt z określonym ProductID. Jeśli nie, zwraca wartość false, wskazując, że żądanie zaktualizowania informacji o produkcie nie powiodło się. W przeciwnym razie aktualizuje pola ProductName i UnitPrice rekordu istniejącego produktu i zatwierdza aktualizację, wywołując metodę TableAdapter Update(), przekazując wystąpienie ProductsRow.

Z tym dodatkiem do naszej ProductsBLL klasy jesteśmy gotowi do utworzenia uproszczonego interfejsu GridView. Otwórz folder DataModificationEvents.aspx w folderze EditInsertDelete i dodaj element GridView do strony. Utwórz nową instancję ObjectDataSource i skonfiguruj ją tak, aby korzystał z klasy ProductsBLL z mapowaniem metody Select() na GetProducts oraz mapowaniem metody Update() na przeciążenie UpdateProduct, które przyjmuje tylko parametry wejściowe: productName, unitPrice, i productID. Rysunek 2 przedstawia kreatora tworzenia źródła danych przy mapowaniu metody ObjectDataSource Update() na nowe przeciążenie metody UpdateProduct klasy ProductsBLL.

Mapowanie metody Update() ObjectDataSource na nowe przeciążenie UpdateProduct

Rysunek 2. Mapowanie metody ObjectDataSource Update() na nowe UpdateProduct przeciążenie (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Ponieważ nasz przykład początkowo będzie potrzebować tylko możliwości edytowania danych, ale nie wstawiania lub usuwania rekordów, poświęć chwilę, aby wyraźnie wskazać, że metody ObjectDataSource z Insert() i Delete() nie powinny być mapowane na żadną z metod klasy ProductsBLL, przechodząc do kart INSERT i DELETE i wybierając (Brak) z listy rozwijanej.

Wybierz (Brak) z listy rozwijanej kart INSERT i DELETE

Rysunek 3. Wybierz pozycję (Brak) z listy rozwijanej kart INSERT i DELETE (Kliknij, aby wyświetlić obraz w pełnym rozmiarze)

Po ukończeniu pracy z tym kreatorem, zaznacz pole wyboru Włącz edytowanie w tagu inteligentnym GridView.

Po zakończeniu pracy kreatora tworzenia źródła danych i powiązaniu go z kontrolką GridView, Visual Studio utworzył składnię deklaratywną dla obu kontrolek. Przejdź do widoku Źródło, aby sprawdzić deklaratywne znaczniki objectDataSource, które przedstawiono poniżej:

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    OldValuesParameterFormatString="original_{0}" SelectMethod="GetProducts"
    TypeName="ProductsBLL" UpdateMethod="UpdateProduct">
    <UpdateParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="unitPrice" Type="Decimal" />
        <asp:Parameter Name="productID" Type="Int32" />
    </UpdateParameters>
</asp:ObjectDataSource>

Ponieważ nie ma mapowań dla metod Insert() i Delete() ObjectDataSource, nie ma sekcji InsertParameters ani DeleteParameters. Ponadto, ponieważ metoda Update() jest mapowana do przeciążenia metody UpdateProduct, które akceptuje tylko trzy parametry wejściowe, sekcja UpdateParameters zawiera tylko trzy wystąpienia Parameter.

Należy pamiętać, że właściwość OldValuesParameterFormatString obiektu ObjectDataSource jest ustawiona na original_{0}. Ta właściwość jest ustawiana automatycznie przez program Visual Studio podczas korzystania z Kreatora konfiguracji źródła danych. Jednak ponieważ nasze metody BLL nie oczekują przekazania oryginalnej wartości ProductID, należy całkowicie usunąć przypisanie tej właściwości ze składni deklaratywnej ObjectDataSource.

Uwaga

Jeśli po prostu wyczyścisz wartość właściwości OldValuesParameterFormatString z okna Właściwości w widoku Projektu, właściwość będzie nadal obecna w składni deklaratywnej, ale zostanie ustawiona na pusty ciąg. Całkowicie usuń właściwość ze składni deklaratywnej lub z okno Właściwości ustaw wartość na wartość domyślną {0}.

Obiekt ObjectDataSource ma tylko UpdateParameters dla nazwy, ceny i identyfikatora produktu, podczas gdy Visual Studio dodało pole BoundField lub CheckBoxField w GridView dla każdego z pól produktu.

GridView zawiera BoundField lub pole wyboru (CheckBoxField) dla każdej z właściwości produktu.

Rysunek 4: GridView zawiera "BoundField" lub "CheckBoxField" dla każdego pola produktu (kliknij, aby wyświetlić obraz w pełnym rozmiarze)

Gdy użytkownik końcowy edytuje produkt i klika przycisk Aktualizuj, funkcja GridView wylicza te pola, które nie były tylko do odczytu. Następnie ustawia wartość odpowiedniego parametru w kolekcji ObjectDataSource UpdateParameters na wartość wprowadzoną przez użytkownika. Jeśli nie ma odpowiedniego parametru, kontrolka GridView dodaje jeden do kolekcji. W związku z tym, jeśli obiekt GridView zawiera pola BoundFields i CheckBoxFields dla wszystkich pól produktu, obiekt ObjectDataSource wywoła przeciążenie UpdateProduct, które przyjmuje wszystkie te parametry, mimo że deklaratywny znacznik ObjectDataSource określa tylko trzy parametry wejściowe (patrz Rysunek 5). Podobnie, jeśli w GridView istnieje kombinacja pól produktów, które nie są tylko do odczytu i które nie odpowiadają parametrom wejściowym przeciążenia UpdateProduct, podczas próby aktualizacji zgłoszony zostanie wyjątek.

Parametry zostaną dodane przez kontrolkę GridView do kolekcji UpdateParameters w obiekcie ObjectDataSource

Rysunek 5. Obiekt GridView doda parametry do kolekcji ObjectDataSource UpdateParameters (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Aby upewnić się, że ObjectDataSource wywołuje przeciążenie UpdateProduct, które przyjmuje wyłącznie nazwę, cenę i identyfikator produktu, musimy ograniczyć GridView do edytowania pól wyłącznie dla ProductName i UnitPrice. Można to osiągnąć, usuwając inne pola BoundFields i CheckBoxFields, ustawiając właściwość tych innych pól ReadOnly na true, lub przez kombinację tych dwóch pól. W tym samouczku po prostu usuńmy wszystkie pola GridView z wyjątkiem pól ProductName i UnitPrice BoundFields, po czym znacznik deklaratywny GridView będzie wyglądać następująco:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
    <Columns>
        <asp:CommandField ShowEditButton="True" />
        <asp:BoundField DataField="ProductName"
          HeaderText="ProductName" SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice"
          SortExpression="UnitPrice" />
    </Columns>
</asp:GridView>

Mimo że przeciążenie UpdateProduct oczekuje trzech parametrów wejściowych, mamy tylko dwa pola typu BoundField w naszym GridView. Jest to spowodowane tym, że productID parametr wejściowy jest wartością klucza podstawowego i przekazywany za pomocą wartości właściwości DataKeyNames dla edytowanego wiersza.

Nasz element GridView wraz z UpdateProduct przeciążeniem umożliwia użytkownikowi edytowanie tylko nazwy i ceny produktu bez utraty żadnego z innych pól produktu.

Interfejs umożliwia edytowanie tylko nazwy i ceny produktu

Rysunek 6. Interfejs umożliwia edytowanie tylko nazwy i ceny produktu (kliknij, aby wyświetlić obraz pełnowymiarowy)

Uwaga

Jak wspomniano w poprzednim samouczku, ważne jest, aby stan widoku GridView był włączony (zachowanie domyślne). Jeśli ustawisz właściwość GridView EnableViewState na wartość false, istnieje ryzyko przypadkowego usunięcia lub edytowania rekordów przez równocześnie działających użytkowników.

UlepszanieUnitPriceformatowania

Chociaż przykład GridView pokazany na rysunku 6 działa, UnitPrice pole nie jest w ogóle sformatowane, co powoduje wyświetlenie ceny, która nie zawiera symboli waluty i ma cztery miejsca dziesiętne. Aby zastosować formatowanie waluty dla wierszy, które nie można edytować, po prostu ustaw UnitPrice właściwość BoundField DataFormatString na {0:c} i jej HtmlEncode właściwość na false.

Ustaw właściwości DataFormatString i HtmlEncode dla UnitPrice odpowiednio

Rysunek 7: Ustaw właściwości UnitPrice, DataFormatString i HtmlEncode zgodnie z wymaganiami (Kliknij, aby wyświetlić pełny rozmiar obrazu)

Dzięki tej zmianie wiersze nieedytowalne formatują cenę jako walutę; jednak edytowany wiersz nadal wyświetla wartość bez symbolu waluty i z czterema miejscami dziesiętnymi.

Nieedytowalne wiersze są teraz formatowane jako wartości walutowe

Rysunek 8. Wiersze, które nie można edytować, są teraz formatowane jako wartości walutowe (kliknij, aby wyświetlić obraz pełnowymiarowy)

Instrukcje formatowania określone we właściwości DataFormatString można zastosować do interfejsu edycji, ustawiając dla właściwości BoundField ApplyFormatInEditMode wartość true (wartością domyślną jest false). Zatrzymaj się chwilę, aby ustawić tę właściwość na true.

Ustaw właściwość ApplyFormatInEditMode pola BoundField UnitPrice na wartość true

Rysunek 9. Ustaw UnitPrice właściwość BoundField ApplyFormatInEditMode na true (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Dzięki tej zmianie wartość UnitPrice wyświetlana w edytowanym wierszu jest również formatowana jako waluta.

Zrzut ekranu przedstawiający widok siatki GridView z wartością UnitPrice edytowanego wiersza sformatowaną jako waluta.

Rysunek 10. Wartość edytowanego wiersza UnitPrice jest teraz sformatowana jako waluta (kliknij, aby wyświetlić obraz pełnowymiarowy)

Jednak zaktualizowanie produktu za pomocą symbolu waluty w polu tekstowym, takiego jak 19,00 USD, zgłasza błąd FormatException. Gdy obiekt GridView próbuje przypisać wartości dostarczone przez użytkownika do kolekcji ObjectDataSource UpdateParameters , nie może przekonwertować UnitPrice ciągu "$19.00" na decimal wymagany przez parametr (patrz Rysunek 11). Aby rozwiązać ten problem, możemy utworzyć procedurę obsługi dla zdarzenia RowUpdating w GridView i przeanalizować dane dostarczone przez użytkownika UnitPrice jako sformatowaną jako walutę decimal.

Zdarzenie GridView RowUpdating przyjmuje jako drugi parametr obiektu typu GridViewUpdateEventArgs, który zawiera NewValues słownik jako jedną z jego właściwości, które zawierają wartości dostarczone przez użytkownika gotowe do przypisania do kolekcji ObjectDataSource UpdateParameters . Możemy zastąpić istniejącą UnitPrice wartość w NewValues kolekcji wartością dziesiętną przeanalizowaną przy użyciu formatu waluty z następującymi wierszami kodu w procedurze RowUpdating obsługi zdarzeń:

protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
  if (e.NewValues["UnitPrice"] != null)
    e.NewValues["UnitPrice"] =
        decimal.Parse(e.NewValues["UnitPrice"].ToString(),
            System.Globalization.NumberStyles.Currency);
}

Jeśli użytkownik poda UnitPrice kwotę (np. "$19.00"), ta kwota zostaje zastąpiona wartością dziesiętną obliczoną przez Decimal.Parse, przetwarzając wartość jako walutę. Będzie to prawidłowo przeprowadzać analizę dziesiętną w przypadku występowania symboli walutowych, przecinków, punktów dziesiętnych itd. i używa wyliczenia NumberStyles w przestrzeni nazw System.Globalization.

Rysunek 11 przedstawia zarówno problem spowodowany symbolami walutowymi w podanym UnitPriceprzez użytkownika elememencie , jak również sposób, w jaki program obsługi zdarzeń gridView RowUpdating może być używany do poprawnego analizowania takich danych wejściowych.

Diagram przedstawiający sposób przetwarzania pola UnitPrice obiektu ObjectDataSource oraz sposobu, w jaki program obsługi zdarzeń RowUpdate obiektu GridView konwertuje ciąg na dziesiętny.

Rysunek 11. Wartość edytowanego wiersza UnitPrice jest teraz sformatowana jako waluta (kliknij, aby wyświetlić obraz pełnowymiarowy)

Krok 2. ZakazNULL UnitPrices

Chociaż baza danych jest skonfigurowana tak, aby zezwalała na wartości NULL w kolumnie UnitPrice tabeli Products, możemy chcieć uniemożliwić użytkownikom tej konkretnej strony określanie wartości NULLUnitPrice. Oznacza to, że jeśli użytkownik nie wprowadzi UnitPrice wartości podczas edytowania wiersza produktu, zamiast zapisywać wyniki w bazie danych, chcemy wyświetlić komunikat informujący użytkownika, że za pośrednictwem tej strony wszystkie edytowane produkty muszą mieć określoną cenę.

Obiekt GridViewUpdateEventArgs przekazany do procedury obsługi zdarzeń kontrolki GridView RowUpdating zawiera Cancel właściwość, która, jeśli jest ustawiona na true, kończy proces aktualizowania. Rozszerzmy procedurę obsługi zdarzeń RowUpdating, aby ustawić e.Cancel na true i wyświetlić komunikat wyjaśniający, dlaczego wartość UnitPrice w kolekcji NewValues to null, jeśli spełniony jest ten warunek.

Zacznij od dodania kontrolki sieci Web o nazwie 'Etykieta' do strony MustProvideUnitPriceMessage. Kontrolka Etykieta będzie wyświetlana, gdy użytkownik nie poda wartości UnitPrice podczas aktualizowania produktu. Ustaw właściwość Label Text na "Musisz podać cenę produktu". Utworzono również nową klasę CSS o nazwie Warning w Styles.css o następującej definicji:

.Warning
{
    color: Red;
    font-style: italic;
    font-weight: bold;
    font-size: x-large;
}

Na koniec ustaw właściwość etykiety CssClass na Warning. Na tym etapie Projektant powinien wyświetlić komunikat ostrzegawczy czcionką w kolorze czerwonym, pogrubioną, kursywą, w bardzo dużym rozmiarze powyżej komponentu GridView, jak pokazano na rysunku 12.

Etykieta została dodana powyżej kontrolki GridView

Rysunek 12. Etykieta została dodana powyżej kontrolki GridView (kliknij, aby wyświetlić obraz pełnowymiarowy)

Domyślnie ta etykieta powinna być ukryta, więc ustaw jej Visible właściwość na false w procedurze obsługi zdarzeń Page_Load :

protected void Page_Load(object sender, EventArgs e)
{
    MustProvideUnitPriceMessage.Visible = false;
}

Jeśli użytkownik próbuje zaktualizować produkt bez określenia UnitPriceelementu , chcemy anulować aktualizację i wyświetlić etykietę ostrzeżenia. Rozszerz procedurę obsługi zdarzeń usługi GridView RowUpdating w następujący sposób:

protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
    if (e.NewValues["UnitPrice"] != null)
    {
        e.NewValues["UnitPrice"] =
            decimal.Parse(e.NewValues["UnitPrice"].ToString(),
                System.Globalization.NumberStyles.Currency);
    }
    else
    {
        // Show the Label
        MustProvideUnitPriceMessage.Visible = true;

        // Cancel the update
        e.Cancel = true;
    }
}

Jeśli użytkownik spróbuje zapisać produkt bez określenia ceny, aktualizacja zostanie anulowana i zostanie wyświetlony pomocny komunikat. Chociaż baza danych (i logika biznesowa) zezwala na NULLUnitPrice-y, ta konkretna strona ASP.NET tego nie robi.

Użytkownik nie może pozostawić wartości UnitPrice pustej

Rysunek 13. Użytkownik nie może pozostawić UnitPrice pustego (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Do tej pory widzieliśmy, jak za pomocą zdarzenia GridView RowUpdating programowo zmienić wartości parametrów przypisanych do kolekcji ObjectDataSource UpdateParameters , a także jak całkowicie anulować proces aktualizacji. Te koncepcje są stosowane w kontrolkach DetailsView i FormView, a także dotyczą wstawiania i usuwania.

Te zadania można również wykonywać na poziomie ObjectDataSource za pomocą procedur obsługi zdarzeń dla zdarzeń Inserting, Updatingi Deleting . Te zdarzenia są uruchamiane przed wywołaniem skojarzonej metody obiektu bazowego i zapewniają ostatnią szansę na zmianę kolekcji parametrów wejściowych lub anulowanie operacji. Procedury obsługi zdarzeń dla tych trzech zdarzeń są przekazywane obiektowi typu ObjectDataSourceMethodEventArgs, który ma dwie interesujące właściwości:

  • Anuluj, co, jeśli jest ustawione na true, anuluje wykonywaną operację
  • InputParameters, który jest kolekcją InsertParameters, UpdateParameters, lub DeleteParameters, w zależności od tego, czy program obsługi zdarzeń jest dla Inserting, Updating, lub Deleting zdarzenia

Aby zilustrować pracę z wartościami parametrów na poziomie ObjectDataSource, dołączmy element DetailsView na naszej stronie, który umożliwia użytkownikom dodawanie nowego produktu. Ten element DetailsView będzie używany do zapewnienia interfejsu do szybkiego dodawania nowego produktu do bazy danych. Aby zachować spójny interfejs użytkownika podczas dodawania nowego produktu, zezwól użytkownikowi na wprowadzanie wartości tylko dla ProductName pól i UnitPrice . Domyślnie te wartości, które nie są podane w interfejsie wstawiania kontrolki DetailsView, zostaną ustawione na NULL wartość bazy danych. Możemy jednak użyć zdarzenia ObjectDataSource Inserting , aby wstrzyknąć różne wartości domyślne, jak zobaczymy wkrótce.

Krok 3. Dostarczanie interfejsu do dodawania nowych produktów

Przeciągnij kontrolkę DetailsView z przybornika do projektanta powyżej kontrolki GridView, wyczyść jej właściwości Height i Width, a następnie powiąż ją z ObjectDataSource już obecnym na stronie. Spowoduje to dodanie pola BoundField lub CheckBoxField dla każdego pola produktu. Ponieważ chcemy użyć tego elementu DetailsView do dodawania nowych produktów, musimy sprawdzić opcję Włącz wstawianie z tagu inteligentnego. Nie ma jednak takiej opcji, ponieważ metoda Insert() dla ObjectDataSource nie jest mapowana na metodę w klasie ProductsBLL (przypomnij sobie, że to mapowanie jest ustawione na wartość (Brak) podczas konfigurowania źródła danych, jak pokazano na Rysunku 3).

Aby skonfigurować ObjectDataSource, wybierz link Konfiguruj źródło danych z metki inteligentnej, co spowoduje uruchomienie kreatora. Pierwszy ekran umożliwia zmianę obiektu bazowego, do którego jest powiązany ObjectDataSource; pozostaw ustawienie ProductsBLL. Następny ekran przedstawia listę mapowań metod ObjectDataSource do metod obiektu bazowego. Mimo że jawnie wskazaliśmy, że metody Insert() i Delete() nie powinny być mapowane na jakiekolwiek metody, jeśli przejdziesz do kart INSERT i DELETE, zobaczysz, że mapowanie istnieje. Dzieje się tak, ponieważ metody ProductsBLLAddProduct i DeleteProduct używają atrybutu DataObjectMethodAttribute, aby wskazać, że są domyślnymi metodami odpowiednio dla Insert() i Delete(). W związku z tym kreator ObjectDataSource wybiera te elementy za każdym razem, gdy zostanie uruchomiony kreator, chyba że zostanie jawnie określona inna wartość.

Pozostaw metodę Insert() wskazującą metodę AddProduct , ale ponownie ustaw listę rozwijaną karty DELETE na wartość (Brak).

Ustaw listę rozwijaną karty INSERT na metodę AddProduct

Rysunek 14. Ustaw listę rozwijaną karty INSERT na metodę AddProduct (kliknij, aby wyświetlić obraz pełnowymiarowy)

Ustaw listę rozwijaną karty DELETE na wartość (Brak)

Rysunek 15. Ustaw listę rozwijaną karty DELETE na (Brak) (Kliknij, aby wyświetlić obraz pełnowymiarowy)

Po wprowadzeniu tych zmian składnia deklaratywna obiektu ObjectDataSource zostanie rozszerzona w celu uwzględnienia InsertParameters kolekcji, jak pokazano poniżej:

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    SelectMethod="GetProducts" TypeName="ProductsBLL"
    UpdateMethod="UpdateProduct" OnUpdating="ObjectDataSource1_Updating"
    InsertMethod="AddProduct" OldValuesParameterFormatString="original_{0}">
    <UpdateParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="unitPrice" Type="Decimal" />
        <asp:Parameter Name="productID" Type="Int32" />
    </UpdateParameters>
    <InsertParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="supplierID" Type="Int32" />
        <asp:Parameter Name="categoryID" Type="Int32" />
        <asp:Parameter Name="quantityPerUnit" Type="String" />
        <asp:Parameter Name="unitPrice" Type="Decimal" />
        <asp:Parameter Name="unitsInStock" Type="Int16" />
        <asp:Parameter Name="unitsOnOrder" Type="Int16" />
        <asp:Parameter Name="reorderLevel" Type="Int16" />
        <asp:Parameter Name="discontinued" Type="Boolean" />
    </InsertParameters>
</asp:ObjectDataSource>

Ponowne uruchomienie kreatora ponownie dodało właściwość OldValuesParameterFormatString. Pośmiń chwilę, aby wyczyścić tę właściwość, ustawiając ją na wartość domyślną ({0}) lub usuwając ją całkowicie ze składni deklaratywnej.

Gdy ObjectDataSource zapewnia funkcje wstawiania, inteligentny tag DetailsView będzie teraz zawierać pole wyboru Włącz możliwość wstawiania; wróć do projektanta i zaznacz tę opcję. Następnie ogranicz element DetailsView, aby zawierał tylko dwa pola BoundFields — ProductName i UnitPrice — oraz CommandField. W tym momencie składnia deklaratywna elementu DetailsView powinna wyglądać następująco:

<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
    <Fields>
        <asp:BoundField DataField="ProductName"
          HeaderText="ProductName" SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice"
          SortExpression="UnitPrice" />
        <asp:CommandField ShowInsertButton="True" />
    </Fields>
</asp:DetailsView>

Rysunek 16 pokazuje tę stronę, gdy jest wyświetlana w przeglądarce w tym momencie. Jak widać, kontrolka DetailsView wyświetla nazwę i cenę pierwszego produktu (Chai). Chcemy jednak wstawić interfejs zapewniający użytkownikowi możliwość szybkiego dodania nowego produktu do bazy danych.

Element DetailsView jest obecnie renderowany w trybie tylko do odczytu

Rysunek 16. Widok Szczegółów jest obecnie renderowany w trybie tylko do odczytu (kliknij, aby wyświetlić obraz pełnowymiarowy)

Aby wyświetlić element DetailsView w trybie wstawiania, musimy ustawić właściwość DefaultMode na wartość Inserting. Spowoduje to renderowanie kontrolki DetailsView w trybie wstawiania po pierwszym odwiedzeniu i utrzymuje go po wstawieniu nowego rekordu. Jak pokazano na rysunku 17, taki element DetailsView zapewnia szybki interfejs dodawania nowego rekordu.

Element DetailsView udostępnia interfejs umożliwiający szybkie dodawanie nowego produktu

Rysunek 17. Widok Szczegółów zawiera interfejs umożliwiający szybkie dodawanie nowego produktu (kliknij, aby wyświetlić obraz pełnowymiarowy)

Gdy użytkownik wprowadzi nazwę i cenę produktu (np. "Acme Water" i 1,99, jak na rysunku 17), a następnie kliknie Wstaw, następuje postback i rozpoczyna się proces wstawiania, który kończy się dodaniem nowego rekordu produktu do bazy danych. Element DetailsView utrzymuje interfejs wstawiania, a element GridView jest automatycznie przywracany do źródła danych w celu uwzględnienia nowego produktu, jak pokazano na rysunku 18.

Produkt

Rysunek 18. Produkt "Acme Water" został dodany do bazy danych

Chociaż element GridView na rysunku 18 tego nie pokazuje, pola produktu, których brakuje w interfejsie DetailsView CategoryID, SupplierID, QuantityPerUnit i tak dalej, mają przypisane wartości bazy danych NULL. Można to zobaczyć, wykonując następujące kroki:

  1. Przejdź do Eksploratora serwera w programie Visual Studio
  2. Rozszerzanie węzła NORTHWND.MDF bazy danych
  3. Kliknij prawym przyciskiem myszy na Products węzeł tabeli bazy danych
  4. Wybierz pozycję Pokaż dane tabeli

Spowoduje to wyświetlenie listy wszystkich rekordów w Products tabeli. Jak pokazano na rysunku 19, wszystkie kolumny naszego nowego produktu inne niż ProductID, ProductNamei UnitPrice mają NULL wartości.

Pola produktu, które nie zostały podane w widoku DetailsView, są przypisane wartości NULL

Rysunek 19. Pola produktu, które nie zostały podane w widoku DetailsView, są wartościami przypisanymi NULL (kliknij, aby wyświetlić obraz pełnowymiarowy)

Możemy chcieć podać wartość domyślną inną niż NULL dla jednej lub większej liczby tych wartości kolumn, ponieważ NULL nie jest najlepszą wartością domyślną albo ponieważ sama kolumna bazy danych nie zezwala na NULL. W tym celu możemy programowo ustawić wartości parametrów kolekcji DetailsView InputParameters . To przypisanie można wykonać w procedurze obsługi zdarzeń dla zdarzenia DetailsView ItemInserting lub zdarzenia ObjectDataSource Inserting . Ponieważ już przyjrzeliśmy się używaniu zdarzeń przed- i po-poziomowych na poziomie kontrolki sieci Web dla danych, przyjrzyjmy się teraz użyciu zdarzeń obiektu ObjectDataSource.

Krok 4. Przypisywanie wartości do parametrówCategoryIDiSupplierID

W tym samouczku wyobraźmy sobie, że w przypadku naszej aplikacji podczas dodawania nowego produktu za pomocą tego interfejsu należy przypisać wartość 1 dla CategoryID i SupplierID. Jak wspomniano wcześniej, obiekt ObjectDataSource zawiera parę zdarzeń wstępnych i po poziomie, które są uruchamiane podczas procesu modyfikacji danych. Po wywołaniu metody Insert(), obiekt ObjectDataSource najpierw zgłasza zdarzenie Inserting, następnie wywołuje metodę, do której została przypisana jego metoda Insert(), a na koniec zgłasza zdarzenie Inserted. Procedura Inserting obsługi zdarzeń daje nam ostatnią szansę na dostosowanie parametrów wejściowych lub całkowite anulowanie tej operacji.

Uwaga

W rzeczywistej aplikacji prawdopodobnie zechcesz pozwolić użytkownikowi określić kategorię i dostawcę lub wybrać tę wartość na podstawie niektórych kryteriów lub logiki biznesowej (zamiast ślepo wybierać identyfikator 1). Niezależnie od tego, w przykładzie pokazano, jak programowo ustawić wartość parametru wejściowego ze zdarzenia pre-level obiektu ObjectDataSource.

Pośmiń chwilę na utworzenie procedury obsługi zdarzeń dla zdarzenia ObjectDataSource Inserting . Zwróć uwagę, że drugi parametr wejściowy programu obsługi zdarzeń jest obiektem typu ObjectDataSourceMethodEventArgs, który ma właściwość dostępu do kolekcji parametrów (InputParameters) i właściwości, aby anulować operację (Cancel).

protected void ObjectDataSource1_Inserting
    (object sender, ObjectDataSourceMethodEventArgs e)
{

}

W tym momencie InputParameters właściwość zawiera kolekcję ObjectDataSource InsertParameters z wartościami przypisanymi z elementu DetailsView. Aby zmienić wartość jednego z tych parametrów, po prostu użyj polecenia: e.InputParameters["paramName"] = value. W związku z tym, aby ustawić CategoryID i SupplierID na wartości 1, dostosuj obsługę zdarzeń Inserting tak, aby wyglądała następująco:

protected void ObjectDataSource1_Inserting
    (object sender, ObjectDataSourceMethodEventArgs e)
{
    e.InputParameters["CategoryID"] = 1;
    e.InputParameters["SupplierID"] = 1;
}

Tym razem podczas dodawania nowego produktu (takiego jak Soda Acme) CategoryID kolumny i SupplierID nowego produktu są ustawione na 1 (patrz Rysunek 20).

Nowe produkty mają teraz wartości CategoryID i SupplierID ustawione na 1

Rysunek 20. Nowe produkty mają teraz wartości CategoryID i SupplierID ustawione na 1 (kliknij, aby wyświetlić obraz pełnowymiarowy)

Podsumowanie

Podczas procesu edytowania, wstawiania i usuwania zarówno kontrola danych sieci Web, jak i obiekt ObjectDataSource przechodzi przez wiele zdarzeń przed i po opublikowaniu. W tym samouczku zbadaliśmy wstępne zdarzenia i pokazaliśmy, jak za ich pomocą można dostosować parametry wejściowe lub całkowicie anulować operację modyfikacji danych, zarówno w przypadku zdarzeń kontrolki danych sieci Web, jak i zdarzeń klasy ObjectDataSource. W następnym samouczku przyjrzymy się tworzeniu i używaniu programów obsługi zdarzeń dla zdarzeń po poziomie.

Szczęśliwe programowanie!

Informacje o autorze

Scott Mitchell, autor siedmiu książek ASP/ASP.NET i założyciel 4GuysFromRolla.com, współpracuje z technologiami internetowymi firmy Microsoft od 1998 roku. Scott pracuje jako niezależny konsultant, trener i pisarz. Jego najnowsza książka to Sams Teach Yourself ASP.NET 2.0 w 24 godzinach. Można go uzyskać pod adresem mitchell@4GuysFromRolla.com.

Specjalne podziękowania

Ta seria samouczków została omówiona przez wielu przydatnych recenzentów. Główni recenzenci tego samouczka to Jackie Goor i Liz Shulok. Chcesz przejrzeć nadchodzące artykuły MSDN? Jeśli tak, napisz do mnie na adres mitchell@4GuysFromRolla.com.