ItemsControl 的行为

发布于 2024-11-19 09:08:38 字数 2937 浏览 4 评论 0原文

我的屏幕上有多个用户控件,但只有其中一个保持活动状态。其他用户控件未显示,但用户可以切换任何不活动的用户控件的活动标志。其中一个 UserControl 包含一个 ItemsControl。

当视图最终初始化时,加载屏幕中第一个活动的 UserControl 后,我需要知道视图中的所有控件,包括由 ItemsControl 生成的控件。

对于 ItemsControl,wpf 不会实例化任何项目,直到它被绘制在包含 UserControl 的屏幕上(所以我已经尝试过,直到启动 Load 事件),因此我找不到视图包含的控件,因为它不存在。

有什么办法可以改变这种行为吗?

我尝试将属性 VirtualizingStackPanel.IsVirtualizing 的值更改为 false,以避免以前的行为,但没有成功。为了说明这一点,我编写了这个视图示例:

<Window x:Class="ContenidoEnTabs.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
    <StackPanel x:Name="spContainer" Orientation="Vertical" VirtualizingStackPanel.IsVirtualizing="False">
        <Button Content="Push" Click="Button_Click" />
    </StackPanel>
</Window>

该视图创建第二个控件,直到用户按下按钮为止不可见:

public partial class MainWindow : Window
{
    private NotPaintedOnInitUserControl controlExtra;

    public MainWindow()
    {
        InitializeComponent();
        controlExtra = new NotPaintedOnInitUserControl();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        spContainer.Children.Add(controlExtra);
    }
}

最初不可见的控件如下所示:

<UserControl x:Class="ContenidoEnTabs.NotPaintedOnInitUserControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d"
         d:DesignHeight="300" d:DesignWidth="300">
    <ItemsControl ItemsSource="{Binding MyCollection}" x:Name="itemsControlTarget" 
              VirtualizingStackPanel.IsVirtualizing="False">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBox x:Name="aTextBox" Width="80" Initialized="ATextBox_Initialized" />
            </DataTemplate>
            </ItemsControl.ItemTemplate>
    </ItemsControl>
</UserControl>

在 CodeBehind 中,我检测何时创建项目

public partial class NotPaintedOnInitUserControl : UserControl
{
    public NotPaintedOnInitUserControl()
    {
        InitializeComponent();
        DataContext = new SimpleListDataContext();
    }

    private void ATextBox_Initialized(object sender, EventArgs e)
    {
    }
}

以及使用的 DataContext:

public class SimpleListDataContext
{
    private List<string> _myCollection;
    public List<string> MyCollection
    {
        get { return _myCollection ?? (_myCollection = new List<string> { "one", "two" }); }
        set { _myCollection = value; }
    }
}

任何想法?

提前致谢。

I have a screen with several UserControls, but only one of them remains active. The other UserControls aren't shown, but the user can switch the active flag of any of those who are not active. One of the UserControl contains an ItemsControl.

I need to know all the controls in the view, including those generated by an ItemsControl, after loading the first UserControl that is active in the screen, when view is finally initialized.

For ItemsControl, wpf didn't instance any item until it was painted on the screen that contains the UserControl (so I've tried, until the Load event is launched), so that I can't found the controls contained by the view because it didn't exist.

Is there any way to change this behavior?

I try to change the value of property VirtualizingStackPanel.IsVirtualizing to false, to avoid the previous behaviour, with no success. To illustrate this, I write this view example:

<Window x:Class="ContenidoEnTabs.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
    <StackPanel x:Name="spContainer" Orientation="Vertical" VirtualizingStackPanel.IsVirtualizing="False">
        <Button Content="Push" Click="Button_Click" />
    </StackPanel>
</Window>

This view creates a second control not visible until the user press the button:

public partial class MainWindow : Window
{
    private NotPaintedOnInitUserControl controlExtra;

    public MainWindow()
    {
        InitializeComponent();
        controlExtra = new NotPaintedOnInitUserControl();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        spContainer.Children.Add(controlExtra);
    }
}

The control not visible initially is as follow:

<UserControl x:Class="ContenidoEnTabs.NotPaintedOnInitUserControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d"
         d:DesignHeight="300" d:DesignWidth="300">
    <ItemsControl ItemsSource="{Binding MyCollection}" x:Name="itemsControlTarget" 
              VirtualizingStackPanel.IsVirtualizing="False">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBox x:Name="aTextBox" Width="80" Initialized="ATextBox_Initialized" />
            </DataTemplate>
            </ItemsControl.ItemTemplate>
    </ItemsControl>
</UserControl>

and in CodeBehind I detect when the Items were created

public partial class NotPaintedOnInitUserControl : UserControl
{
    public NotPaintedOnInitUserControl()
    {
        InitializeComponent();
        DataContext = new SimpleListDataContext();
    }

    private void ATextBox_Initialized(object sender, EventArgs e)
    {
    }
}

And the DataContext used:

public class SimpleListDataContext
{
    private List<string> _myCollection;
    public List<string> MyCollection
    {
        get { return _myCollection ?? (_myCollection = new List<string> { "one", "two" }); }
        set { _myCollection = value; }
    }
}

Any ideas?

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

噩梦成真你也成魔 2024-11-26 09:08:38

如果您希望 WPF 为不属于视图的控件生成树,则可以通过强制运行布局来“水化”并布局该控件。像这样的事情应该有效:

public partial class MainWindow : Window
{
    private NotPaintedOnInitUserControl controlExtra;

    public MainWindow()
    {
        InitializeComponent();

        controlExtra = new NotPaintedOnInitUserControl();

        // Force the control to render, even though it's not on the screen yet.
        var size = new Size(this.Width, this.Height);
        var rect = new Rect(new Point(0,0), size);
        controlExtra.Measure(size);
        controlExtra.Arrange(rect);
        controlExtra.InvalidateVisual();
        controlExtra.UpdateLayout();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        spContainer.Children.Add(controlExtra);
    }
}

不确定这是否是您所要求的。如果不是,请澄清第 2 段。

If you want WPF to generate the tree for a control that isn't part of the view, you can "hydrate" and layout the control by forcing the layout to run. Something like this should work:

public partial class MainWindow : Window
{
    private NotPaintedOnInitUserControl controlExtra;

    public MainWindow()
    {
        InitializeComponent();

        controlExtra = new NotPaintedOnInitUserControl();

        // Force the control to render, even though it's not on the screen yet.
        var size = new Size(this.Width, this.Height);
        var rect = new Rect(new Point(0,0), size);
        controlExtra.Measure(size);
        controlExtra.Arrange(rect);
        controlExtra.InvalidateVisual();
        controlExtra.UpdateLayout();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        spContainer.Children.Add(controlExtra);
    }
}

Not sure if this is what you're asking. If not, please clarify paragraph 2.

深府石板幽径 2024-11-26 09:08:38

看一下 LogicalTreeHelper.GetChildren(myUiElement)

它查看逻辑树而不是视觉树,因此它检查结构而不需要加载控件来获取视觉结构

在下面的控件中找到的是控件的名称即 myDatagrid

您还可以对其进行调整以获取特定控件的所有子项,即

FindChildInVisualTree(this, "mydatagrid"); // assumming this a UIElement (i.e. your in the code behind)

使用以下命令找到该控件,然后使用 LogicalTreeHelper 获取它的所有子项。

 public static UIElement FindChildInVisualTree(UIElement view, string controlToFind)
    {
        UIElement control = null;
        try
        {
            if (view != null)
            {
                if ((view as FrameworkElement).Name.ToUpper() == controlToFind.ToUpper())
                {
                    control = view;
                }
                else
                {
                    DependencyObject depObj = view as DependencyObject;
                    if (depObj != null)
                    {
                        foreach (var item in LogicalTreeHelper.GetChildren(depObj))
                        {
                            control = FindChildInVisualTree(item as UIElement, controlToFind);
                            if (control != null)
                            {
                                break;
                            }
                        }
                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw new ApplicationException("Error finding child control: " + controlToFind, ex);
        }
        return control;
    }

Have a look at LogicalTreeHelper.GetChildren(myUiElement)

This looks at the logical tree rather than the visual tree so it examines the structure without needing to have loaded the control to get the visual structure

In the below control to find is the name of the contorl i.e. myDatagrid

You could also adapt this to just get all the children of a particular control i.e.

FindChildInVisualTree(this, "mydatagrid"); // assumming this a UIElement (i.e. your in the code behind)

find the control using the below then using LogicalTreeHelper get all it's children.

 public static UIElement FindChildInVisualTree(UIElement view, string controlToFind)
    {
        UIElement control = null;
        try
        {
            if (view != null)
            {
                if ((view as FrameworkElement).Name.ToUpper() == controlToFind.ToUpper())
                {
                    control = view;
                }
                else
                {
                    DependencyObject depObj = view as DependencyObject;
                    if (depObj != null)
                    {
                        foreach (var item in LogicalTreeHelper.GetChildren(depObj))
                        {
                            control = FindChildInVisualTree(item as UIElement, controlToFind);
                            if (control != null)
                            {
                                break;
                            }
                        }
                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw new ApplicationException("Error finding child control: " + controlToFind, ex);
        }
        return control;
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文