2015-02-23 12 views
5

Uprościłem ten problem tak bardzo, jak tylko mogę. Zasadniczo nadpisuję wartość "null" combobox. Tak więc, jeśli wybrany element zostanie usunięty, powraca do "(null)". Niestety zachowanie tego jest złe, trafiłem usunąć, element ObservableCollection został usunięty, a więc powiązanie właściwości zostało zaktualizowane i zwraca element "(zerowy)" zgodnie z oczekiwaniami. Ale wygląd combobox pokazuje puste. Jednak wartość, do której jest przypisana, jest poprawna ... ten problem można odtworzyć za pomocą poniższego kodu.WPF DisplayMemberPath nie aktualizuje się, gdy SelectedItem został usunięty

Aby odtworzyć ten problem, należy wybrać element i nacisnąć przycisk usunięcia. Zauważ w tym miejscu wywoływana jest następująca linia (po usunięciu zaznaczonego elementu). Jest to dobre miejsce do przełamania.

   if (m_Selected == null) 
      { 
       return Items[0]; //items 0 is ItemNull 
      } 

zauważyć także, że mam attmpted go naprawić poprzez wymuszenie aktualizacji nieruchomości na DisplayMemberPath. To nie zadziałało.

MainWindow.xaml

<Window x:Class="WPFCodeDump.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <StackPanel> 
     <ComboBox ItemsSource="{Binding Items}" SelectedItem="{Binding Selected, Mode=TwoWay}" DisplayMemberPath="Name"></ComboBox> 
     <Button Click="ButtonBase_OnClick">Remove Selected</Button> 
    </StackPanel> 
</Window> 

MainWindowViewModel.cs

using System.Collections.ObjectModel; 
using System.ComponentModel; 
using System.Runtime.CompilerServices; 
using System.Windows.Input; 

namespace WPFCodeDump 
{ 
    public abstract class ViewModelBase : INotifyPropertyChanged 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 

     protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "") 
     { 
      PropertyChangedEventHandler handler = PropertyChanged; 
      if (handler != null) 
      { 
       handler(this, new PropertyChangedEventArgs(propertyName)); 
      } 
     } 
    } 

    //Item class 
    public class Item : ViewModelBase 
    { 
     public Item(string name) 
     { 
      m_Name = name; 
     } 

     public string Name 
     { 
      get { return m_Name; } 
     } 
     private string m_Name; 

     public void ForcePropertyUpdate() 
     { 
      OnPropertyChanged("Name"); 
     } 
    } 

    //Item class 
    public class ItemNull : Item 
    { 
     public ItemNull() 
      : base("(null)") 
     { 
     } 
    } 

    class MainWindowViewModel : ViewModelBase 
    { 
     public MainWindowViewModel() 
     { 
      m_Items.Add(new ItemNull()); 
      for (int i = 0; i < 10; i++) 
      { 
       m_Items.Add(new Item("TestItem" + i)); 
      } 
      Selected = null; 
     } 

     //Remove selected command 
     public void RemoveSelected() 
     { 
      Items.Remove(Selected); 
     } 

     //The item list 
     private ObservableCollection<Item> m_Items = new ObservableCollection<Item>(); 
     public ObservableCollection<Item> Items 
     { 
      get { return m_Items; } 
     } 

     //Selected item 
     private Item m_Selected; 
     public Item Selected 
     { 
      get 
      { 
       if (m_Selected == null) 
       { 
        return Items[0]; //items 0 is ItemNull 
       } 
       return m_Selected; 
      } 
      set 
      { 
       m_Selected = value; 
       OnPropertyChanged(); 
       if(m_Selected!=null) m_Selected.ForcePropertyUpdate(); 
      } 
     } 
    } 
} 

MainWindow.xaml.cs

using System.Windows; 

namespace WPFCodeDump 
{ 


    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
      DataContext = new MainWindowViewModel(); 
     } 

     private void ButtonBase_OnClick(object sender, RoutedEventArgs e) 
     { 
      ((MainWindowViewModel) DataContext).RemoveSelected(); 
     } 
    } 
} 

Wynik:

Result after pressing remove

+0

* wróć Pozycje [0] * ... wróć z czego? Co to ma zrobić? Z pewnością potrzebujesz 'Selected = Items [0]' (zakładając, że 'Items [0]' jest rzeczywistym elementem z kolekcji związanej z danymi). – Sheridan

+0

Czy próbowałeś ustawić 'UpdateSourceTrigger = PropertyChanged' na swojej SelectedItem-Binding? – Tomtom

+0

Zwraca ItemNull(), która jest instancją wewnątrz m_Items – Asheh

Odpowiedz

3

Niezły problem wiążący się z tym problemem. Ale jak zawsze, to nasza wina, nie ich. :)

Emisja jest (są), przy użyciu DisplayMemberPath z SelectedItem. The DisplayMemberPath nie daje f *** o zmienionym SelectedItem.

Co trzeba zrobić, aby rozwiązać ten problem, są dwie rzeczy:

Po pierwsze, w sposobie RemoveSelected, należy ustawić właściwość Selected null (aby wymusić aktualizację na wiązanie):

public void RemoveSelected() 
{ 
    Items.Remove(Selected); 
    Selected = null; 
} 

Następnie w XAML-definition, zmień związany właściwość:

<ComboBox ItemsSource="{Binding Items}" 
      SelectedValue="{Binding Selected, Mode=TwoWay}" 
      DisplayMemberPath="Name"/> 

Binding właściwość SelectedValue poprawnie u pdate wyświetlany tekst w ComboBox.

+0

Wow to działa. Czy istnieje sposób na obejście "Selected = null"? W punkcie w kodzie niestety nie wiem o Selected (tak jak w moim przykładzie). mogę obejść ten jednak subskrybując przypadku ItemsSource OnCollectionChanged .... – Asheh

+0

przykro być bardziej jasne. Mój wybrany element nie ma informacji o kolekcji, do której jest przypisany. – Asheh

+0

Zgadnij, musisz to zrobić w miejscu, które wie o obu ...? – Herdo

Powiązane problemy