2011-12-02 64 views
2

我遇到一些麻煩,我的DataGrid:C#WPF DataGrid不動態排序上的數據更新

當我更新一些數據(從模型),它顯示在我的DataGrid,但如果點擊頁眉當我更新現有數據時,對列進行排序時,它開始橫向移動。

這裏的 1例 小號

  • 如果我添加了新的價值,它不會在年底出現(像它的時候我不排序數據網格),但它顯示在錯誤的地方(每次都是一樣的地方)。
  • 如果我更新一個現有的值,那麼當它需要時,順序不會改變。

我見過多次的答案,但有人說DataGridTextColumn不應該是一個問題... 所以我想知道是不是因爲字典... 我知道,與新的第一個問題數據與字典有關。

對象。

public class Player : INotifyPropertyChanged 
{ 
    private string _id; 
    private string _name; 
    private int _damage; 
    private int _heal; 
    private int _dps; 
    private int _hps; 
    private int _time = 1;    

    public Player(string id, string name) 
    { 
     _name = name; 
     _id = id; 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    public string Id 
    { 
     get { return _id; } 
     private set 
     { 
      _id = value; 
     } 
    } 

    public string Name 
    { 
     get { return _name; } 
     private set 
     {     
      _name = value;     
      NotifyPropertyChanged("Name");     
     } 
    } 

    public int Damage 
    { 
     get { return _damage; } 
     set 
     { 
      _damage = value;     
      NotifyPropertyChanged("Damage"); 
      Dps = _damage/_time; 
     } 
    } 

    public int Heal 
    { 
     get { return _heal; } 
     set 
     { 
      _heal = value; 
      NotifyPropertyChanged("Heal"); 
      Hps = _heal/_time; 
     } 
    } 

    public int Dps 
    { 
     get { return _dps; } 
     private set 
     { 
      _dps = value; 
      NotifyPropertyChanged("Dps"); 
     } 
    } 

    public int Hps 
    { 
     get {return _hps; } 
     private set 
     { 
      _hps = value; 
      NotifyPropertyChanged("Hps"); 
     } 
    } 

    public int Time 
    { 
     get { return _time; } 
     set 
     { 
      _time = value; 
      Dps = _damage/_time; 
      Hps = _heal/_time; 
     } 
    } 

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

} 

的ObservableCollection

public sealed class ShortList 
{ 
    private static readonly ShortList instance = new ShortList(); 
    private ObservableCollection<Player> playerList = new ObservableCollection<Player>(); 

    private ShortList() 
    { 
    } 

    public static ShortList getShortList 
    { 
     get 
     { 
      return instance; 
     } 
    } 

    public ObservableCollection<Player> getPlayerList 
    { 
     get 
     { 
      return playerList; 
     } 
    } 

    public void updatePlayer(string id, string name, int damage, int heal, int time) 
    { 
     Player player; 
     player = findPlayer(id); 
     if (player != null) 
     {     
      player.Damage = player.Damage + damage; 
      player.Heal = player.Heal + heal; 
      player.Time = player.Time + time;     
     } 
     else 
     {     
      player = new Player(id, name); 
      player.Damage = damage; 
      player.Heal = heal; 
      player.Time = time; 
      playerList.Add(player); 
     }      
    } 

    public void clear() 
    { 
     playerList.Clear(); 
    } 

    private Player findPlayer(string id) 
    { 
     foreach (Player p in playerList) 
     { 
      if (p.Id == id) 
      { 
       return p; 
      } 
     } 
     return null; 
    } 

} 

XAML

<DataGrid AutoGenerateColumns="False"Name="playerDataGrid" IsReadOnly="True" ItemsSource="{Binding}"> 
    <DataGrid.Columns> 
     <DataGridTextColumn Header="Nom" Binding="{Binding Name}" MinWidth="35"/> 
     <DataGridTextColumn Header="Degats" Binding="{Binding Damage}" MinWidth="45" /> 
     <DataGridTextColumn Header="DPS" Binding="{Binding Dps}" MinWidth="29" /> 
     <DataGridTextColumn Header="Soins" Binding="{Binding Heal}" MinWidth="35" /> 
     <DataGridTextColumn Header="HPS" Binding="{Binding Hps}" MinWidth="29" /> 
    </DataGrid.Columns> 
</DataGrid> 

窗口

public partial class MiniParser : Window 
{ 
     public MiniParser() 
     {    
      InitializeComponent(); 
      playerDataGrid.ItemsSource = ShortList.getShortList.getPlayerList; 
      temporyFill(); 
     } 

     private void temporyFill() 
     { 
      ShortList.getShortList.updatePlayer("1234", "ABCD", 100, 0, 2); 
      ShortList.getShortList.updatePlayer("1234", "ABCD", 100, 0, 0); 
      ShortList.getShortList.updatePlayer("123", "ABC", 50, 0, 1); 
      ShortList.getShortList.updatePlayer("234", "ABC", 0, 50, 1); 
      ShortList.getShortList.updatePlayer("345", "BCD", 1000, 25, 25); 
      ShortList.getShortList.updatePlayer("456", "CDE", 250, 0, 25); 
     } 

     private void startMI_Click(object sender, RoutedEventArgs e) 
     { 
      ShortList.getShortList.updatePlayer("5678", "BABA", 100, 100, 100); 
      ShortList.getShortList.updatePlayer("1234", "ABCD", 100, 0, 0);    
     } 
} 

當然後面的代碼最落後的代碼是有測試目的......但這個想法是模型正在更新,視圖需要反映更改(即使是排序)。

回答

3

我找到了解決辦法,到目前爲止好:

的問題是,當你在一個對象,它已經在你的ObservableCollection改變一個字段的值的ObservableCollection不會觸發事件「CollectionChanged」。 (可能因爲你不改變對它的引用)。

下面是一個例子:

ObservableCollection<MyObject> myCollection = new ObservableCollection<MyObject>(); 
myCollection.add("CollectionChanged","Yes"); 
//Let's say I had a method to find a object with the first string and to change the second string 
myCollection.change("CollectionChanged", "No"); 

正如您可以猜到,當我改變了我的現有對象的字段的CollectionChanged沒有觸發第二部分...

所以我實施的解決方案如下:

class ObsCollection<T> : ObservableCollection<T> 
    { 
     public void UpdateCollection() 
     { 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(
          NotifyCollectionChangedAction.Reset)); 
     } 
    } 

所有你所要做的就是創建新的類型的集合,然後當你更改現有對象的字段值,調用UpdateCollection()會見HOD。

該解決方案是由吳雪松。

我想說雷切爾也是一個很大的幫助。

+1

的情況下根據MSDN,復位手段發現「大大改變了集合的內容。」是否有一種更細化的方式讓排序工作?對於小型收藏品,重置似乎沒問題,但對於頻繁更新的大型收藏品可能會造成問題。 – KornMuffin

+0

如果將其從ObservableCollection更改爲BindingList,該怎麼辦?我想BindingList會在單個項目更改時引發收集已更改的事件。 – Cesar

3

當屬性更新時,您不會提升PropertyChanged事件。這意味着name""更改爲​​的新項目或已更改的現有項目不會引發PropertyChanged事件,以使UI知道值已更改且需要更新。

要修復它,使屬性在PropertyChanged事件發生變化時引發它。

public class Player : INotifyPropertyChanged 
{ 
    private string _name; 
    public string Name 
    { 
     get { return _name; } 
     set 
     { 
      if (_name != value) 
      { 
       _name = value; 
       RaisePropertyChanged("Name"); 
      } 
     } 
    } 

另外,我重新閱讀你的問題,我不知道你與ObservableDictionary做什麼,但我建議你改變這種讓你的DataGrid直接綁定到ObservableCollection<Player>。我懷疑這是你問題的一部分。

,看起來像這樣
var playerCollection = new ObservableCollection<Player>(); 
playerCollection.Add(new Player { Name = "Test 1" }); 
playerCollection.Add(new Player { Name = "Test 2" }); 
playerCollection.Add(new Player { Name = "Test 3" }); 

playerDataGrid.ItemsSource = playerCollection; 
+0

我覺得我做你的要求(見第一哨的變化),但遺憾的是沒有解決該問題的第二部分。感謝你的幫助到目前爲止,我希望我能自己找到它,但我會繼續尋找我的救贖。 – Tooc

+0

@ user1078049我相信'NotifiyPropertyChanged'區分大小寫,因此請嘗試調整您的調用以使用正確的大小寫。 'NotifyPropertyChanged(「Name」);' – Rachel

+0

謝謝,但並沒有改變任何東西...... – Tooc

0

移動任何代碼:

this.NotifyPropertyChanged("somepropertyname"); 

到您的屬性setter方法。這是制定者在那裏的原因。

此外,我第二個答案suggestig你使用ObservableCollection<T>而不是你的ObservableDictionary<TKey,TValue>。它們對於WPF綁定非常常見。