【问题标题】:C# WPF Datagrid doesn't dynamically sort on data updateC# WPF Datagrid 不会对数据更新进行动态排序
【发布时间】:2012-01-11 18:41:12
【问题描述】:

我的数据网格有问题:

当我更新一些数据(来自模型)时,它会显示在我的 DataGrid 上,但是如果单击标题以对列进行排序,当我更新现有数据时它会开始横向移动。

这里是 2 1 个例子s

  • 如果我添加一个新值,它不会出现在最后(就像我不对数据网格进行排序时那样),但它会显示在错误的位置(每次都在同一个位置)。罢工>
  • 如果我更新现有值,则顺序永远不会在需要时更改。

我看过多个答案,但有人说 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);            
        }
}

当然,后面的大部分代码都是为了测试目的......但想法是模型正在更新,视图需要反映变化(甚至是排序)。

【问题讨论】:

    标签: c# wpf datagrid observablecollection


    【解决方案1】:

    当属性更新时,您不会引发 PropertyChanged 事件。这意味着具有name 的新项目从"" 更改为"Test",或更改的现有项目不会引发 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&lt;Player&gt;。我怀疑这是你的问题的一部分。

    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;
    

    【讨论】:

    • 我想我按照您的要求做了(请参阅第一篇文章中的更改),但遗憾的是没有纠正问题的第二部分。感谢您到目前为止的帮助,我希望我能自己找到它,但我会继续在这里寻找我的救赎。
    • @user1078049 我相信NotifiyPropertyChanged 区分大小写,因此请尝试调整您的调用以使用正确的大小写。 NotifyPropertyChanged("Name");
    • Jivlain 写道“在 WPF 的 DataGrid 控件中,如果将列设置为默认列类型之一(如 DataGridTextColumn 或 DataGridCheckBoxColumn),对该列进行排序,然后更改其值,网格将自动重新排序。”在另一个线程上,但对我来说不是这样......我在网上发现根本不是这样
    【解决方案2】:

    我找到了解决方案,到目前为止一切顺利:

    问题在于,当您更改已在 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() 方法。

    这个解决方案来自吴雪松。

    我想说 Rachel 也帮了大忙。

    【讨论】:

    • 根据 MSDN,Reset 的意思是“集合的内容发生了巨大的变化”。有没有更细粒度的方式让排序工作?重置对于小型收藏似乎没问题,但对于频繁更新的大型收藏可能是个问题。
    • 如果将其从 ObservableCollection 更改为 BindingList 会怎样?我想当个别项目发生变化时,BindingList 会引发集合变化事件。
    【解决方案3】:

    移动任何如下所示的代码:

    this.NotifyPropertyChanged("somepropertyname");
    

    进入你的属性的setter方法。这就是二传手的目的。

    另外,我建议您使用ObservableCollection&lt;T&gt; 而不是ObservableDictionary&lt;TKey,TValue&gt;。它们在 WPF 绑定中非常常见。

    【讨论】:

      猜你喜欢
      • 2017-06-09
      • 2010-12-24
      • 2011-08-12
      • 2010-12-10
      • 2017-10-06
      • 2012-01-21
      • 2010-11-29
      • 2013-10-22
      • 2012-07-15
      相关资源
      最近更新 更多