WPF:是否可以多次在ItemsControl上显示一个项目?

时间:2017-08-06 06:23:22

标签: wpf itemscontrol

我想创建一个控件,但我真的不知道怎么用英文命名它,这就是为什么我真的不知道谷歌要用什么。

所以,如果已经有了它的名称和/或如果已经有一个具有以下功能的控件,请告诉我。

我的控制是某种ItemsControl,但有一点不同。如果它包含的项目太少而无法完全填充视口,则它应该再次从第一个项目开始,直到视口完全填满。

因此,如果视口有空间让我们说五个项目,而我的ItemsSource只包含两个项目,那么控件应该显示项目1,然后是2,然后是1,然后是2,然后是1。

将其视为WPF相当于电视新闻频道底部的新闻频道。它绕过可用的项目,如果它到达终点,它会再次从第一个项目开始,两者之间没有间隙。

我已经尝试为此创建自己的面板,但我找不到在此面板中多次显示一个项目的方法。这甚至可能吗?

你会如何创建这样的控件?我可以将其基于默认ItemsControl,还是必须从Control继承并从头开始?

感谢您的想法和正确的方向。

编辑1:

我尝试了以下内容,以遵循答案1中的建议。

我创建了RecurringEnumerator(Of T)

Imports System.Collections.ObjectModel

Public Class RecurringEnumerator(Of T)
    Implements IEnumerator(Of T)

    Private _internal As ICollection(Of T)
    Private _currentIndex As Integer

    Public Sub New(ByVal internal As ICollection(Of T))
        If (internal Is Nothing) Then
            Throw New ArgumentNullException("internal")
        End If

        _internal = internal
        _currentIndex = -1
    End Sub

    Public ReadOnly Property Current As T Implements IEnumerator(Of T).Current
        Get
            Return _internal(_currentIndex)
        End Get
    End Property

    Public ReadOnly Property CurrentObject As Object Implements IEnumerator.Current
        Get
            Return _internal(_currentIndex)
        End Get
    End Property

    Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
        If (_internal.Count = 0) Then
            Return False
        End If

        _currentIndex += 1

        If (_currentIndex >= _internal.Count) Then
            _currentIndex -= _internal.Count
        End If

        Return True
    End Function

    Public Sub Reset() Implements IEnumerator.Reset
        _currentIndex = -1
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
    End Sub

End Class

然后我在RecurringEnumerator(Of T)中使用了此RecurringCollection(Of T):     公共类RecurringCollection(Of T)         实现ICollection(Of T)

    Private _enumerator As RecurringEnumerator(Of T)
    Private _internal As ObjectModel.Collection(Of T)

    Public Sub New()
        _enumerator = New RecurringEnumerator(Of T)(Me)
        _internal = New ObjectModel.Collection(Of T)
    End Sub

    Public Function GetEnumerator() As IEnumerator(Of T) Implements IEnumerable(Of T).GetEnumerator
        Return _enumerator
    End Function

    Public Function GetObjectEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
        Return _enumerator
    End Function

    Public Sub Add(ByVal item As T) Implements ICollection(Of T).Add
        _internal.Add(item)
    End Sub

    Public Sub Clear() Implements ICollection(Of T).Clear
        _internal.Clear()
    End Sub

    Public Function Contains(ByVal item As T) As Boolean Implements ICollection(Of T).Contains
        Return _internal.Contains(item)
    End Function

    Public Sub CopyTo(ByVal array() As T, ByVal arrayIndex As Integer) Implements ICollection(Of T).CopyTo
        _internal.CopyTo(array, arrayIndex)
    End Sub

    Public ReadOnly Property Count As Integer Implements ICollection(Of T).Count
        Get
            Return _internal.Count
        End Get
    End Property

    Public ReadOnly Property IsReadOnly As Boolean Implements ICollection(Of T).IsReadOnly
        Get
            Return False
        End Get
    End Property

    Public Function Remove(ByVal item As T) As Boolean Implements ICollection(Of T).Remove
        Return _internal.Remove(item)
    End Function

End Class

但是在这个RecurringCollection(Of T)中加入三个短字符串,并在整个集合中分别显示每个字符串的消息框,结果显示StackOverflowException而没有显示至少一个消息框。

之前我没有创建自定义集合,所以我不确定我是否做得对。

1 个答案:

答案 0 :(得分:-1)

您可以创建专门的集合,而不是尝试操纵ItemsControl。我在下面写了一个模板。为简洁起见,我省略了错误检查和其他ICollection<T>方法。您可以轻松地将方法委派给内部列表。

public class RecurringList<T> : ICollection<T>
{
    private readonly List<T> _items = new List<T>();

    public int DesiredCount { get; set; }
    public int Count => _items.Count > 0 ? DesiredCount : 0;

    public bool IsReadOnly => false;

    public IEnumerator<T> GetEnumerator()
    {
        if (_items.Count == 0)
        {
            yield break;
        }

        int count = Math.Max(DesiredCount, _items.Count);

        for (int i = 0; i < count; i++)
        {
            yield return _items[i % _items.Count];
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public void Add(T item)
    {
        _items.Add(item);
    }

    public void Clear()
    {
        _items.Clear();
    }

    public bool Contains(T item)
    {
        return _items.Contains(item);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        _items.CopyTo(array, arrayIndex);
    }

    public bool Remove(T item)
    {
        return _items.Remove(item);
    }
}