如何创建用户控件以在 WinForms 中显示其他用户控件的集合?

How to create user control for displaying collection of other user controls in WinForms?

我需要创建一个用户控件 MyTypeListControl 来显示类型 MyType 的对象集合,为每个对象使用一个用户控件 MyTypeDisplayControl 实例。

这样我就可以

  1. MyTypeListControl 的实例添加到我的 WinForm,然后
  2. 加载 MyType
  3. 的集合
  4. 将其分配给 MyTypeListControl 的数据源。

在结果中,它应该在 MyTypeListControl 的实例中生成并显示适当数量的 MyTypeDisplayControl 个实例。

如果我需要显示属性列表 - 等效项是 DataGrid,其中 MyType 的特定字段分配给特定 DataGrid 的列,但我想查看每个 MyType 项作为用户控件 - 比 DataGrid 提供的行更强大的视觉表示和功能。

这可能吗?

I found this SO resource如何创建My集合类型,但这只是问题解决的一小部分...

这很容易(如果您知道怎么做的话)并且不需要像您最初想象的那么多努力(至少对于处理少于 100 个项目的简单实现而言)。

所以首先让我们创建一个 MyType:

public class MyType
{
    public static MyType Empty = new MyType(String.Empty, DateTime.MinValue);

    public MyType(string myName, DateTime myBirthday)
    {
        MyName = myName;
        MyBirthday = myBirthday;
    }

    public DateTime MyBirthday { get; private set; }

    public string MyName { get; private set; }
}

接下来我们需要一个 MyTypeControl:

public partial class MyTypeControl : UserControl
{
    private MyType _MyType;
    private Label labelBirthday;
    private Label labelName;
    private Label labelSeparator;

    public MyTypeControl()
    {
        InitializeComponent();
    }

    public event EventHandler MyTypeChanged;

    public MyType MyType
    {
        get { return _MyType; }
        set
        {
            if (_MyType == value)
                return;

            _MyType = value ?? MyType.Empty;
            OnMyTypeChanged(EventArgs.Empty);
        }
    }

    protected virtual void OnMyTypeChanged(EventArgs eventArgs)
    {
        UpdateVisualization();
        RaiseEvent(MyTypeChanged, eventArgs);
    }

    protected void UpdateVisualization()
    {
        SuspendLayout();

        labelName.Text = _MyType.MyName;
        labelBirthday.Text = _MyType.MyBirthday.ToString("F");
        labelBirthday.Visible = _MyType.MyBirthday != DateTime.MinValue;

        ResumeLayout();
    }

    private void InitializeComponent()
    {
        labelName = new Label();
        labelBirthday = new Label();
        labelSeparator = new Label();
        SuspendLayout();
        labelName.Dock = DockStyle.Top;
        labelName.Location = new Point(0, 0);
        labelName.TextAlign = ContentAlignment.MiddleCenter;
        labelBirthday.Dock = DockStyle.Top;
        labelBirthday.TextAlign = ContentAlignment.MiddleCenter;
        labelSeparator.BorderStyle = BorderStyle.Fixed3D;
        labelSeparator.Dock = DockStyle.Top;
        labelSeparator.Size = new Size(150, 2);
        Controls.Add(labelSeparator);
        Controls.Add(labelBirthday);
        Controls.Add(labelName);
        MinimumSize = new Size(0, 48);
        Name = "MyTypeControl";
        Size = new Size(150, 48);
        ResumeLayout(false);
    }

    private void RaiseEvent(EventHandler eventHandler, EventArgs eventArgs)
    {
        var temp = eventHandler;

        if (temp != null)
            temp(this, eventArgs);
    }
}

然后是我们神奇的列表控件:

public class MyTypeListControl : UserControl
{
    private ObservableCollection<MyType> _Items;

    public MyTypeListControl()
    {
        AutoScroll = true;
        _Items = new ObservableCollection<MyType>();
        _Items.CollectionChanged += OnItemsCollectionChanged;
    }

    public Collection<MyType> Items
    {
        get { return _Items; }
    }

    private void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        UpdateVisualization();
    }

    private void UpdateVisualization()
    {
        SuspendLayout();
        Controls.Clear();

        foreach (var item in _Items)
        {
            var control = new MyTypeControl { MyType = item, Dock = DockStyle.Top };
            Controls.Add(control);
            Controls.SetChildIndex(control, 0);
        }

        ResumeLayout();
    }
}

现在只需在您的表单或父控件中创建列表控件并用一些有意义的值填充它:

myTypeListControl.Items.Add(new MyType("Adam", DateTime.UtcNow.Add(-TimeSpan.FromDays(365 * 40))));
myTypeListControl.Items.Add(new MyType("Eva", DateTime.UtcNow.Add(-TimeSpan.FromDays(365 * 38))));