我在使用WPF时遇到了一个小问题,并将我的listbox / listview绑定到自定义列表。
此列表包含IEnumerator& IEnumerable接口已实现。如果我将控件绑定到那些,我永远不会看到该列表的第一个对象。
当我是gridview时,它确实显示了我的第一个对象。因此,由于某种原因,listbox / listview正在执行不同的操作来枚举我的自定义列表。
我的绑定用于两种设置完全相同的方式,使用我的ViewModel上的公共属性。
Binding(我的PersonObject有一个公共属性ProjectList,它获取我正在谈论的自定义列表)。
public Person Person
{
get
{
return this._person;
}
set
{
if (this._person != value)
{
this._person = value;
RaisePropertyChanged("Person");
}
}
}
XAML:
<ListBox ItemsSource="{Binding Path=Person.ProjectList,UpdateSourceTrigger=PropertyChanged}" AlternationCount="2" ItemContainerStyle="{StaticResource CustomListBoxItemStyle}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} - {1}">
<Binding Path="Name" />
<Binding Path="Number" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} - {1}">
<Binding Path="StartDate" />
<Binding Path="EndDate" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Customlist类:
public class ProjectList : DeletableSupport, IEnumerator, IEnumerable
{
private IList<Project> _pList;
private int _position;
public ProjectList()
{
this._pList = new ActivatableList<Project>();
this._position = -1;
}
public void Add(Project p)
{
Activate(ActivationPurpose.Write);
this._pList.Add(p);
}
public void Remove(Project p)
{
Activate(ActivationPurpose.Write);
this._pList.Remove(p);
}
public int Count()
{
Activate(ActivationPurpose.Read);
return this._pList.Count();
}
public bool Contains(Project p)
{
Activate(ActivationPurpose.Read);
return this._pList.Contains(p);
}
public Project this[int i]
{
get
{
Activate(ActivationPurpose.Read);
return this._pList[i];
}
set
{
Activate(ActivationPurpose.Write);
this._pList[i] = value;
}
}
public static ProjectList operator +(ProjectList pList, Project p)
{
pList.Add(p);
return pList;
}
public static ProjectList operator -(ProjectList pList, Project p)
{
pList.Remove(p);
return pList;
}
#region IEnumerable Members
public IEnumerator GetEnumerator()
{
Activate(ActivationPurpose.Read);
return (IEnumerator)this;
}
#endregion
#region IEnumerator Members
public object Current
{
get
{
try
{
Activate(ActivationPurpose.Read);
return this._pList[_position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
public bool MoveNext()
{
Activate(ActivationPurpose.Read);
this._position++;
if (_position < this._pList.Count)
{
return true;
}
else
{
return false;
}
}
public void Reset()
{
Activate(ActivationPurpose.Write);
_position = -1;
}
#endregion
}
Activate来自db4o,ActivatableList实现IList
答案 0 :(得分:3)
我会在这里冒险猜测,只是为了测试我的通灵调试技巧:)
ListBox / ListView正在使用IEnumerable.Any()(或一些等价物)来测试列表是否为空。这是返回true,因此它使用您的IEnumerable实现实际迭代列表。
请注意,它没有在您的类上调用reset,这意味着将跳过Any()调用检索到的第一个元素。
通常在IEnumerable上调用GetEnumerator将为您的类返回一个新的IEnumerator实例,但您的实际列表实现包含枚举器的所有状态。您是否考虑过如果您第二次将此列表传递给ListBox会发生什么?我认为你根本看不到任何东西。
好的,那么如何解决这个问题呢?好吧,根据您拥有的代码,只要有人调用GetEnumerator(),您就可以调用Reset()。 但是你所拥有的实现不是线程安全的(现在可能不是问题,但是谁知道将来如何使用它?)。如果你真的不想使用像ObservableCollection这样的东西来存储你的项目列表,我至少会看看从GetEnumerator方法中返回一个单独的IEnumerator实例,其中包含枚举过程的所有状态。