我有一个datarepeater,在datarepeater的每一行都有一个datagridview。
当我将数据添加到第一个datagridview和第二个时,我得到了这个 -
然后,如果我向下滚动到页面下方的datarepeater行,然后滚动到顶部,我们得到这个 -
注意项目已改变位置。如果我要向许多datagridviews添加行,当我滚动时会变得非常混乱。
为什么会发生这种情况的任何想法?
答案 0 :(得分:1)
我在以下设置中遇到了类似的问题:
我会过滤(或不过滤)我的列表并从转发器中选择项目。但是当我滚动时,我的选定行将不会被跟踪。我滚动时选择了随机行。
我认为您可能遇到了同样的问题。我没有证据证明我说的是什么,我也不能在那个时候找到答案,但我认为这与转发器的工作方式有关。
它根据显示的项目(在特定时间可见的项目)指定您的项目(行)索引。这样,可以在重复控制的同时实现快速可滚动组件。
想象一下,如果每行有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));
}
此代码没有看到编译器,但它应该让您走上正确的轨道。
总结一下:
这需要很长时间才能找到并实施,但希望对您来说更容易:)