none
DataGrid的诡异现象 RRS feed

  • 问题

  • 有一些DataGrid,在xaml里是这样声明的:

            <DataGrid Name="dgList" AutoGenerateColumns="False" IsReadOnly="True" CanUserAddRows="True" ItemsSource="{Binding}">
              <DataGrid.Columns>
                <DataGridTextColumn Header="编号" Binding="{Binding Path=NO}"/>
                <DataGridTextColumn Header="名称" Binding="{Binding Path=Name}"/>
                <DataGridTextColumn Header="描述" Binding="{Binding Path=Description}"/>
                <DataGridCheckBoxColumn Header="启用" Binding="{Binding Path=En}"/>
              </DataGrid.Columns>
            </DataGrid>
    

    上面这个例子的对应类的声明如下:

    public class Level : INotifyPropertyChanged
      {
    
        private string _Name;
        public virtual string Name
        {
          get
          {
            return _Name;
          }
          set
          {
            if (value != _Name)
            {
              _Name = value;
              PropChanged();
            }
          }
        }
    
        private int _id;
        public virtual int ID 
        {
          get
          {
            return _id;
          }
          set
          {
            if (value != _id)
            {
              _id = value;
              PropChanged();
            }
          }
        }
    
        private string _no;
        public virtual string NO 
        {
          get
          {
            return _no;
          }
          set
          {
            if (value != _no)
            {
              _no = value;
              PropChanged();
            }
          }
        }
    
        private string _desc;
        public virtual string Description 
        {
          get
          {
            return _desc;
          }
          set
          {
            if (value != _desc)
            {
              _desc = value;
              PropChanged();
            }
          }
        }
    
        private bool _en;
        public virtual bool En 
        {
          get
          {
            return _en;
          }
          set
          {
            if (value != _en)
            {
              _en = value;
              PropChanged();
            }
          }
        }
    
        #region 属性更新通知
        public virtual event PropertyChangedEventHandler PropertyChanged;
        protected void PropChanged()
        {
          PropertyChangedEventHandler handler = PropertyChanged;
          if (handler != null)
          {
            _isChanged = true;
            string name = new StackTrace().GetFrame(1).GetMethod().Name.Substring(4);
            handler(this, new PropertyChangedEventArgs(name));
          }
        }
        #endregion
      }
    

    我先定义一个集合:

    List<Level> ldl;
    

    然后给集合赋值:

    ldl = GetList();
    

    再绑定到DataGrid的ItemsSource属性:

    Binding bind = new Binding();
    bind.Source = ldl;
    bind.Path = new PropertyPath(".");
    bind.Mode = BindingMode.OneWay;
    
    dgList.SetBinding(DataGrid.ItemsSourceProperty, bind);
    

    接着我把在DataGrid里选中的对象(dgList.SelectedItem)传递到其它地方修改,于是诡异的现象发生了:


    第一种情况:在其它地方修改后,DataGrid里对应的对象会同步变化。


    第二种情况:在其它地方修改后,DataGrid里对应的对象不会同步变化,然而我通过调试发现,DataGrid对应的对象其它已经是修改后的值了,只是DataGrid还是显示原来的值。例如dgList.Items[0]对象的Name属性是"MyName",修改后是"MyName is Test",这时dgList显示的还是"MyName",但是dgList.Items[0]的Name属性这个时候已经是"MyName is Test"。


    第三种情况:DataGrid里的一些对象在其它地方修改后,会同步显示在DataGrid里,而另一些则不会同步显示在DataGrid里。

    期望各位朋友来分析一下,问题究竟出在哪里。
    我在这里先谢谢了!

     

    2010年8月20日 17:54

答案

  • 您好,

    我知道您是用跟踪堆栈的方法来获取当前属性名称。这种方法一般在调试时用。

    在您的代码里您绑定了一个List, 您可以用ObservableCollection试试。我感觉问题可能是集合改变的时候没有及时通知UI层,所以刷新除了问题,您可以参考下面的代码:
    http://msdn.microsoft.com/en-us/library/ms748365.aspx

    Aland Li


    Please mark the replies as answers if they help and unmark if they don't. This can be beneficial to other community members reading the thread.
    2010年8月24日 7:12
    版主

全部回复

  • 您好,

    能否对一下代码进行一下详细的解释:
    protected void PropChanged()
        {
          PropertyChangedEventHandler handler = PropertyChanged;
          if (handler != null)
          {
            _isChanged = true;
            string name = new StackTrace().GetFrame(1).GetMethod().Name.Substring(4);
            handler(this, new PropertyChangedEventArgs(name));
          }
        }
    我觉得问题可能就出在这里。我们一般是直接传属性名的,比如在En 属性的set方法里触发事件,我们边传"En"作为属性名给PropertyChangedEventArgs。

    Aland Li


    Please mark the replies as answers if they help and unmark if they don't. This can be beneficial to other community members reading the thread.
    2010年8月23日 9:24
    版主
  • 感谢你的回复!

    这里我是使用反射来获取更改的属性的名称,而不用使用传递过来的属性名称。

    2010年8月23日 13:18
  • 您好,

    我知道您是用跟踪堆栈的方法来获取当前属性名称。这种方法一般在调试时用。

    在您的代码里您绑定了一个List, 您可以用ObservableCollection试试。我感觉问题可能是集合改变的时候没有及时通知UI层,所以刷新除了问题,您可以参考下面的代码:
    http://msdn.microsoft.com/en-us/library/ms748365.aspx

    Aland Li


    Please mark the replies as answers if they help and unmark if they don't. This can be beneficial to other community members reading the thread.
    2010年8月24日 7:12
    版主