我有一个数据中继器,在数据中继器的每一行都有一个数据网格视图。
当我将数据添加到第一个 datagridview 和第二个时,我得到了这个 -
然后,如果我要向下滚动到页面下方的数据中继器行,然后滚动到顶部,我们会得到这个 -
请注意项目已更改位置。如果我要向许多 datagridviews 添加行,当我滚动时它会变得非常混乱。
任何想法为什么会发生这种情况?
我有一个数据中继器,在数据中继器的每一行都有一个数据网格视图。
当我将数据添加到第一个 datagridview 和第二个时,我得到了这个 -
然后,如果我要向下滚动到页面下方的数据中继器行,然后滚动到顶部,我们会得到这个 -
请注意项目已更改位置。如果我要向许多 datagridviews 添加行,当我滚动时它会变得非常混乱。
任何想法为什么会发生这种情况?
我在以下设置中遇到了类似的问题:
我会过滤(或不过滤)我的列表并从转发器中选择项目。但是当我滚动时,我选择的行不会被跟踪。当我滚动时选择了随机行。
我想你可能会遇到同样的问题。我没有证据证明我在说什么,当时我也找不到关于 SO 的答案,但我认为这与中继器的工作方式有关。
它根据显示的项目(在特定时间可见的项目)指定您的项目(行)索引。通过这种方式,可以快速滚动组件,同时重复控制。
想象一下,如果您每行有 10 个控件并有 30.000 行要显示会怎样。如果中继器必须创建 300.000 个控件,您认为会发生什么情况?
出于这个原因(我再次猜测,这些是我的假设,因为文档非常稀缺 - 正如您现在可能知道的那样)中继器只为适合您的中继器区域的项目创建控件并回收它们。
这意味着,如果您对索引 XX 上的项目进行某种操作并滚动,由于项目不在同一个索引中,中继器将翻转,因为当您滚动时会重新计算索引。
好的,现在我已经回答了您关于发生了什么的问题,让我们看看如何解决它:
首先,添加一个Label
到ItemTemplate
您的中继器。此标签将用于绑定您的项目Id
属性(或类似的东西)。此外,将您的标签 Visible 属性设置为 false 以保持隐藏。
在我的表单上,我添加了这些字段:
// I use an observable collection to be notified when it changes
private ObservableCollection<YourItem> _allItems =
new ObservableCollection<YourItem>();
private BindingSource _bindingSource;
然后将您的集合绑定到重复的(我在 OnLoad 中执行此操作)
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
...
_bindingSource = new BindingSource();
_bindingSource.DataSource = _allItems;
// my hidden label // All my items have an Id property
_labelHiddenId.DataBindings.Add("Text", BindingSource, "Id");
_dataRepeaterList.DataSource = _bindingSource;
_allItems.CollectionChanged += AllItems_CollectionChanged;
}
我的听众:
protected override void AllItems_CollectionChanged(object sender,
NotifyCollectionChangedEventArgs e)
{
RefreshRepeater();
}
我的刷新方法:
protected void RefreshRepeater(bool search = false)
{
if (_dataRepeaterList.InvokeRequired)
{
_dataRepeaterList.Invoke((Action)(() => { RefreshRepeater(search); }));
return;
}
_bindingSource.DataSource = null; // Clear binding source first
_bindingSource.DataSource = _allItems.ToList();
_dataRepeaterList.DataSource = null; // Clear datasource first
_dataRepeaterList.DataSource = _bindingSource;
_dataRepeaterList.Refresh();
}
我的绘制项方法,这是我填写大部分行信息的地方:
protected override void DataRepeater_DrawItem(object sender,
DataRepeaterItemEventArgs e)
{
var dataSourceEntity = GetObjectFromDataSource(e.DataRepeaterItem);
var checkedComponent = _checkedItems.SingleOrDefault(
x => x.Equals(dataSourceEntity));
// Get current item control to fill. Something like
var grid = e.DataRepeaterItem.Controls["yourgridiew"] as DataGridView;
// Do stuff, you are messing with the right object :)
}
还有我的最后一篇:
protected override T GetObjectFromDataSource(DataRepeaterItem dataRepeaterItem)
{
if (dataRepeaterItem == null)
return null;
var hiddenIdLabel = (Label)dataRepeaterItem.Controls[_labelHiddenId.Name];
return _allItems.FirstOrDefault((entity) => entity.Id.ToString().Equals(hiddenIdLabel.Text));
}
这段代码没有看到编译器,但它应该让你走上正确的轨道。
把它们加起来:
这需要很长时间才能找到和实施,但希望对您来说会更容易:)