2010-12-15 15 views
16

Mam DataGrid powiązane z kolekcji IEditableObject.WPG DataGrid wywołuje BeginEdit na obiekcie IEditableObject dwa razy?

Teraz, gdy kliknę dwukrotnie w komórce, zostanie ona otwarta do edycji.

Zabawne jest to, że: BeginEdit będzie wywoływany dwa razy. Czasem dla tego samego obiektu EditableObject, ale czasami dla dwóch różnych obiektów (szczególnie gdy używam PgDn do momentu, w którym trafiam na koniec DataGrid), najpierw zostanie wywołana właściwa nazwa, a następnie inny element z kolekcji, który nigdy wcześniej nie był ostry .

EndEdit jest również wywoływana dwa razy, ale zawsze dla wybranej pozycji, nie dla niewłaściwej.

Czy to znany problem? Wszelkie obejścia, aby uzyskać tylko (prawo) jedno powiadomienie.

+0

Brzmiało interesująco, więc sprawdziłem swoje DataGrid, które jest również powiązane z ObservableCollection i nie doświadczyłem tego ...? Moja reprezentacja to jeden obiekt w wierszu, czy przypadkiem łączysz obiekty, które implementują IEditableObject lub coś podobnego? –

+0

Interesujące. Mój obiekt implementuje tylko IEditableObject i INotifyPropertyChanged, więc nie ma łączenia. Moja ObservableCollection jest jednak opakowana w niestandardowy ListCollectionView. I włączyłem kolumnę do właściwości klasy w moim obiekcie IEditableObject, a nie bezpośrednio do właściwości obiektu IEditableObject. Przynajmniej teraz mam powód, by sprawdzić moje źródło, dzięki! – Sam

+0

Przykłady MSDN zawsze zawierają flagę, która uniemożliwia BeginEdit wykonywanie swoich zadań, gdy jest wywoływana w dowolnym momencie, ale w pierwszej kolejności. Z mojego doświadczenia wynika, że ​​tak, to się nazywa wiele razy. – peterG

Odpowiedz

20

Jeśli spojrzeć na ślad stosu w debugger gdy BeginEdit nazywa, będziesz Zobacz, że za pierwszym razem jest to widok kolekcji nazywający go, a po raz drugi to BindingGroup.

Problem polega na tym, że istnieją dwie rzeczy, które według obu są odpowiedzialne za stan IEditableObject. Gdy WPF udostępnia domyślny widok kolekcji, będzie szukał IEditableObject obiektów w kolekcji i wywoła BeginEdit i EndEdit lub CancelEdit w odpowiedzi na wywołania do odpowiednich metod IEditableCollectionView. Ale również, BindingGroup wywoła metody IEditableObject w odpowiedzi na wywołania BeginEdit i CommitEdit lub CancelEdit.

DataGrid wykorzystuje obie funkcje: po uruchomieniu i kompletne edycje z rzędu, to powiadamia IEditableCollectionViewi się BindingGroup i obie z tych rzeczy, myślę, że to jest ich odpowiedzialność z kolei, aby przejść dalej i powiadomić realizację IEditableObject na podstawowy obiekt źródłowy.

Wygląda więc jak błąd w DataGrid - powoduje, że dwa różne obiekty wywołują BeginEdit (i powiązane metody). A to dlatego, że korzysta z edytowalnych widoków kolekcji i grup powiązań - na pierwszy rzut oka te nie zostały zaprojektowane do użycia w tym samym czasie na tych samych obiektach, w sposób, w jaki używa ich DataGrid.

Powodem, dla którego nie widzisz tego problemu z siatką w Toolkit jest to, że wygląda na nieco starszą wersję - porównując kod z tym, co Reflector pokazuje dla .NET 4.0, zobaczysz, że .NET 4.0 DataGrid ma dodatkowy kod (nową metodę, EnsureItemBindingGroup i pewien powiązany kod w MeasureOverride i OnRowValidationRulesChanged), który zapewnia, że ​​grupa wiążąca zawsze istnieje, niezależnie od tego, czy o to prosisz, czy nie. Jeśli więc zestaw narzędzi WPF zostanie zaktualizowany, prawdopodobnie będzie miał podobną funkcję, chyba że zostanie naprawiony.(Przypuszczam, że jeśli użyjesz bieżącej wersji - w lutym 2010 r., Kiedy to piszę - zestawu narzędzi WPF i użyjesz właściwości ItemBindingGroup, aby poprosić o jawnie grupę wiążącą, zobaczysz dokładnie ten sam problem.)

To nie wyjaśnia, w jaki sposób można uzyskać połączenia z obiektami losowymi, zgodnie z opisem. Nie mogę tego zaszkodzić. Ale wyjaśnia podwójne połączenia na wybranym obiekcie. Najlepszym rozwiązaniem wydaje się kodowanie obiektów źródłowych, aby tolerowały podwójne połączenia.

3

Mam ten sam problem przy użyciu DataGrid .NET Framework 4.

Add Reference do ostatniej wersji WPFToolkit

Dodaj

xmlns:dg="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit" 

i zmienić <DataGrid> z <dg:DataGrid>

+0

Fajne i interesujące. Czy jest to inna wersja, lub dlaczego to rozwiązuje problem? – Sam

+1

jest inny –

4

Nie jestem pewien, co byś użył do przerwania zdarzenia BeginEdit zanim to się stanie, ale dla EndEdit zrobi się prosty znacznik isDirty. W swojej klasie podmiot, który implementuje IEditableObject, dodać następujące:

private bool _isDirty = false; 

    #region IEditableObject Members 

    public void BeginEdit() 
    { 
     // Bug Fix: Windows Controls call EndEdit twice; Once 
     // from IEditableCollectionView, and once from BindingGroup. 
     // This makes sure it only happens once after a BeginEdit. 
     _isDirty = true; 
    } 

    public void CancelEdit() { } 

    public void EndEdit() 
    { 
     if (ItemEndEdit != null && _isDirty) 
     { 
      _isDirty = false; 
      ItemEndEdit(this); 
     } 
    } 

    #endregion 
+0

Powinieneś ustawić _isDirty = false w metodzie CancelEdit. –

0

+1 @IanGriffiths dla diagonsing problemu. Jeśli chodzi o rozwiązanie (lub raczej obejście), możesz policzyć liczbę "oczekujących" zmian. To oznacza coś takiego:

Powiązane problemy