向列表框添加控件时触发的事件

3
我想知道当ListBox中添加ListBoxItems时触发的事件。请注意,我不希望在数据更改时触发事件,而是在控件添加时触发事件。
我已经参考了这个答案,他们说使用CollectionChanged事件,它会在集合更改时触发。所以我不能使用它,因为它在控件添加到VisualTree之前触发。
你可能会想为什么我需要这个。我只是想将listbox的宽度更改为最宽项的宽度。如果您对我要实现的内容更感兴趣,请查看我的代码:
private void SomeEvent(object sender, ............... e)
{
    double greatestWidth = 0;

    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(sidebar) - 1; i++)
    {
        ListBoxItem li = VisualTreeHelper.GetChild(sidebar, i) as ListBoxItem;
        li.HorizontalAlignment = HorizontalAlignment.Center;
    }

    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(sidebar) - 1; i++)
    {
        ListBoxItem li = VisualTreeHelper.GetChild(sidebar, i) as ListBoxItem;
        if (li.Width > greatestWidth)
        {
            greatestWidth = li.Width;
        }
    }

    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(sidebar) - 1; i++)
    {
        ListBoxItem li = VisualTreeHelper.GetChild(sidebar, i) as ListBoxItem;
        li.HorizontalAlignment = HorizontalAlignment.Stretch;
    }
}

更新:

class ResizablePanel : StackPanel
{
    protected override Size MeasureOverride(Size constraint)
    {
        Size calculatedSize = base.MeasureOverride(constraint);

        foreach (ListBoxItem li in this.Children)
        {
            li.HorizontalAlignment = HorizontalAlignment.Center;
        }

        double greatestWidth = 0;

        foreach (ListBoxItem li in this.Children)
        {
            if (li.Width > greatestWidth)
            {
                greatestWidth = li.Width;
            }
        }

        foreach (ListBoxItem li in this.Children)
        {
            li.HorizontalAlignment = HorizontalAlignment.Stretch;
        }

        calculatedSize = new Size(greatestWidth, calculatedSize.Height);

        return calculatedSize;
    }
}

为什么你要用代码来做这件事,如果你将水平对齐设置为Stretch,它也可以通过样式来完成。 - yo chauhan
@ethicallogics 是的,我知道可以使用样式来实现。但我想要有些不同的东西。我想改变所有项目的宽度,使它们保持相同的同时,它们的宽度应该与包含最多字符文本的项目的宽度完全相等。 - Vishal
@Vishal,使大小与最大项相同也可以在不手动控制的情况下实现。我认为你的根本问题并不是你所问的。你能否发布一些关于你期望的屏幕截图?无论如何,你可以监听所需控件的父级更改事件,以了解何时将控件添加到列表框中。 - pushpraj
@pushpraj 我的根本问题实际上就是我所问的。我应该监听哪个控件的父级更改事件?你能否展示一个不需要手动控制的演示来满足我的需求? - Vishal
你能否提供一个示例,说明你是如何将项目添加到列表框(侧边栏)中的?从代码中我可以看出,你正在计算最大项的宽度并将其拉伸。作为另一种方法,你可以使用自定义面板来控制列表框,从而完全掌控它。 - pushpraj
@pushpraj 我正在将数据库中的项目添加到模型中,然后再添加到视图模型和视图中。您能否展示如何创建自定义面板以及如何计算其宽度? - Vishal
2个回答

3

如讨论的那样,以下是您如何掌控大多数大小方面的方法

首先定义一个新面板,并重写方法MeasureOverride

namespace CSharpWPF
{
    class MyPanel : StackPanel
    {
        protected override Size MeasureOverride(Size constraint)
        {
            Size calculatedSize = base.MeasureOverride(constraint);
            foreach (ListBoxItem item in this.Children)
            {
                //your logic with each item
            }
            return calculatedSize;
        }
    }
}

每当添加或删除任何项或需要改变布局,例如调整容器大小时,将调用MeasureOverride方法。

foreach (ListBoxItem item in this.Children)假设您只使用ListBox。您可以根据需要更改它。

然后将此新面板用作

<ListBox xmlns:l="clr-namespace:CSharpWPF">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <l:MyPanel />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
</ListBox>

采用这种方法,您可以更有效地控制大小

详细了解请阅读FrameworkElement.MeasureOverride


查看示例后,您需要做出以下更改以获得所需结果:

  • Margin="10,5,10,5"设置为侧边栏ListBox

  • 在侧边栏ListBox中添加HorizontalAlignment="Right"

  • 从metro.xaml第35行ContentPresenter中删除HorizontalAlignment="Center"

  • 在metro.xaml第51行设置<Setter Property="HorizontalAlignment" Value="Stretch" />

  • 在第52行添加<Setter Property="TextBlock.TextAlignment" Value="Right" />


你可以在这里下载:https://drive.google.com/file/d/0B5WyqSALui0bQlhmY0ZNOF9GbW8/edit?usp=sharing - Vishal
好的,现在告诉我需要什么?如果您能够附上屏幕截图,那就更好了。似乎视图有点复杂,无法自动调整大小。需要重新布局相同的内容。 - pushpraj
点击“交易”按钮。现在看侧边栏。特别是所选项目的宽度。它看起来非常糟糕。 - Vishal
不,我希望所选项目的宽度等于该列表中最宽的列表项的宽度。 - Vishal
让我们在聊天中继续这个讨论 - pushpraj
显示剩余6条评论

0
您可以监听类似于 Items CollectionChanged 的事件。
        public Window1()
    {
        InitializeComponent();
        ((INotifyCollectionChanged)mylistbox.Items).CollectionChanged += myListBox_CollectionChanged;
    }

        private void myListBox_CollectionChanged(object sender,NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            foreach (var item in e.NewItems)
            {

            }
        }
    }

此外,您可以直接获取项目,而无需使用VisualTreeHelper。


1
如果我理解正确的话,这将提供项目,而 OP 正在寻找控件。 - pushpraj
你在代码中看到哪个控件正在使用VisualTree获取ListBoxItem。ListBoxItem li = VisualTreeHelper.GetChild(sidebar, i) as ListBoxItem; - yo chauhan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接