DataGridView滚动点击后跳到顶部
DataGridView jumps to the top after scrolling and clicking
我有一个带过滤功能的 DataGridView。当应用过滤器时,滚动位置返回到顶部,并且网格中的数据按预期更新。当我然后使用滚动条向下滚动然后单击一行时,滚动再次跳回到顶部并且选择了错误的行。然后我再次向下滚动并单击,没有重置。这是我预期的行为。
我明白为什么会出现第一次跳跃,因为网格已经有效地反弹到新的来源。但是,为什么滚动和点击后又跳回上去,就有点伤脑筋了。我试过同时使用 BindingList 和 BindingSource。我已经尝试在 DataGridView 上调用各种更新和刷新以及位置重置,以尝试以编程方式而不是在用户单击时引发第二次重置。有什么想法吗?
唯一的问题是我使用带有数据绑定的 MVVM 模式来近似我们在网络上使用的 knockout.js。从功能上讲,这应该与 txtPartNumberQuery_OnChanged(){RebindGrid();}
我在花时间写完之后就想通了,所以...我想我会回答我自己的问题。
查看模型:
public string PartQueryString {
get
{
return _partQueryString;
}
set
{
_partQueryString = value;
//observe this value and trigger a search when it changes
this.PartMaster.DataSource = _model.SearchPartMaster(_partQueryString);
}
}
查看:
private void ConfigureGridView()
{
gvPartMaster.AutoGenerateColumns = false;
gvPartMaster.Columns.Add(Common.Helper.GetBasicGridViewColumn<DataGridViewTextBoxColumn>("Number", "Part Number"));
gvPartMaster.Columns.Add(Common.Helper.GetBasicGridViewColumn<DataGridViewTextBoxColumn>("Description", "Part Description" ));
gvPartMaster.Columns.Add(Common.Helper.GetBasicGridViewColumn<DataGridViewTextBoxColumn>("ManufacturerDescription", "Manufacturer" ));
gvPartMaster.Columns.Add(Common.Helper.GetBasicGridViewColumn<DataGridViewTextBoxColumn>("CategoryDescription", "Category" ));
gvPartMaster.Columns.Add(Common.Helper.GetBasicGridViewColumn<DataGridViewTextBoxColumn>("Specs", "Specs"));
gvPartMaster.ColumnHeadersDefaultCellStyle.WrapMode = DataGridViewTriState.False;
gvPartMaster.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
}
private void ApplyBindings()
{
txtPartNumberQuery.DataBindings.Add("Text", _viewModel, "PartQueryString", false, DataSourceUpdateMode.OnPropertyChanged);
gvPartMaster.DataSource = _viewModel.PartMaster;
}
这里有两个问题:
- 文本框上的数据绑定在失去焦点时会额外触发一次,即使值并没有真正改变。
- 点击滚动条不构成失去焦点。
如果将 2 和 2 放在一起,您会发现数据网格不是在调整滚动条时反弹,而是在尝试单击该行时反弹。众所周知,重新绑定 datagridview 会将滚动重置回顶部。
我的解决方案是在重新绑定gridview之前确保过滤条件已经改变。
public string PartQueryString {
get
{
return _partQueryString;
}
set
{
if (_partQueryString != value)
{
_partQueryString = value;
//observe this value and trigger a search when it changes
this.PartMaster.DataSource = _model.SearchPartMaster(_partQueryString);
_view.UpdateGridViewPosition();
}
}
}
Functionally, this shouldn't differ from something like txtPartNumberQuery_OnChanged(){RebindGrid();}
这实际上是一个糟糕的假设,因为 TextChanged 事件不会像数据绑定那样触发两次。
我有一个带过滤功能的 DataGridView。当应用过滤器时,滚动位置返回到顶部,并且网格中的数据按预期更新。当我然后使用滚动条向下滚动然后单击一行时,滚动再次跳回到顶部并且选择了错误的行。然后我再次向下滚动并单击,没有重置。这是我预期的行为。
我明白为什么会出现第一次跳跃,因为网格已经有效地反弹到新的来源。但是,为什么滚动和点击后又跳回上去,就有点伤脑筋了。我试过同时使用 BindingList 和 BindingSource。我已经尝试在 DataGridView 上调用各种更新和刷新以及位置重置,以尝试以编程方式而不是在用户单击时引发第二次重置。有什么想法吗?
唯一的问题是我使用带有数据绑定的 MVVM 模式来近似我们在网络上使用的 knockout.js。从功能上讲,这应该与 txtPartNumberQuery_OnChanged(){RebindGrid();}
我在花时间写完之后就想通了,所以...我想我会回答我自己的问题。
查看模型:
public string PartQueryString {
get
{
return _partQueryString;
}
set
{
_partQueryString = value;
//observe this value and trigger a search when it changes
this.PartMaster.DataSource = _model.SearchPartMaster(_partQueryString);
}
}
查看:
private void ConfigureGridView()
{
gvPartMaster.AutoGenerateColumns = false;
gvPartMaster.Columns.Add(Common.Helper.GetBasicGridViewColumn<DataGridViewTextBoxColumn>("Number", "Part Number"));
gvPartMaster.Columns.Add(Common.Helper.GetBasicGridViewColumn<DataGridViewTextBoxColumn>("Description", "Part Description" ));
gvPartMaster.Columns.Add(Common.Helper.GetBasicGridViewColumn<DataGridViewTextBoxColumn>("ManufacturerDescription", "Manufacturer" ));
gvPartMaster.Columns.Add(Common.Helper.GetBasicGridViewColumn<DataGridViewTextBoxColumn>("CategoryDescription", "Category" ));
gvPartMaster.Columns.Add(Common.Helper.GetBasicGridViewColumn<DataGridViewTextBoxColumn>("Specs", "Specs"));
gvPartMaster.ColumnHeadersDefaultCellStyle.WrapMode = DataGridViewTriState.False;
gvPartMaster.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
}
private void ApplyBindings()
{
txtPartNumberQuery.DataBindings.Add("Text", _viewModel, "PartQueryString", false, DataSourceUpdateMode.OnPropertyChanged);
gvPartMaster.DataSource = _viewModel.PartMaster;
}
这里有两个问题:
- 文本框上的数据绑定在失去焦点时会额外触发一次,即使值并没有真正改变。
- 点击滚动条不构成失去焦点。
如果将 2 和 2 放在一起,您会发现数据网格不是在调整滚动条时反弹,而是在尝试单击该行时反弹。众所周知,重新绑定 datagridview 会将滚动重置回顶部。
我的解决方案是在重新绑定gridview之前确保过滤条件已经改变。
public string PartQueryString {
get
{
return _partQueryString;
}
set
{
if (_partQueryString != value)
{
_partQueryString = value;
//observe this value and trigger a search when it changes
this.PartMaster.DataSource = _model.SearchPartMaster(_partQueryString);
_view.UpdateGridViewPosition();
}
}
}
Functionally, this shouldn't differ from something like txtPartNumberQuery_OnChanged(){RebindGrid();}
这实际上是一个糟糕的假设,因为 TextChanged 事件不会像数据绑定那样触发两次。