【问题标题】:WPF - How to detect when new Visual child elements are added?WPF - 如何检测何时添加了新的 Visual 子元素?
【发布时间】:2016-11-27 15:15:28
【问题描述】:

基于一些自定义安全设置,我将窗口子控件更改为只读和禁用。为此,我在窗口加载时循环遍历子控件。

这很好用。 99% 完美。

在我的窗口中,我有一个 ItemsControl,其内容基于 ComboBox。更改 ComboBox,ItemsControl 中的子控件再次数据绑定。但是,安全性(只读/禁用)不再是真的。

在您跳到解决方案之前,我知道我可以处理 ComboBox changed 事件;但是,我有很多这样的框,并且无论我的开发人员向窗口/表单添加什么内容,我都没有一个可以在窗口级别应用的通用解决方案(想想:基础)。

我的问题(很抱歉,引入时间太长了)是,我如何检测由于某些动态活动(如数据绑定)而将新子项添加到窗口的时间?是否有 NewChildAdded 事件?是否有 DataBindingJustChangedThings 事件?

一定有什么。

如果您的解决方案包含计时器,则无需回复。我的表单太复杂了,无法处理额外的负载 - 滴答之间的延迟实在是一个安全问题。

您可能在想,只需将外部容器设置为只读或禁用即可。但这会对扩展器、多行文本框和列表框等内容产生负面影响。这种方法不够细化。当然,这是我们之前开始迭代的地方。

如果您的解决方案包含样式,则需要说明我如何在每个控件的基础上覆盖您的方法。某些控件(如复选框)无法禁用,因为它们在 UI 布局中有用途。

很抱歉有限制,但我计划在生产中使用该解决方案。

谢谢。

【问题讨论】:

    标签: wpf events visual-tree


    【解决方案1】:

    你试过OnVisualChildrenChanged吗?

        /// <summary>
        /// Handle visual children being added or removed
        /// </summary>
        /// <param name="visualAdded">Visual child added</param>
        /// <param name="visualRemoved">Visual child removed</param>
        protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
        {
            // Track when objects are added and removed
            if (visualAdded != null)
            {
                // Do stuff with the added object
            }
            if (visualRemoved != null)
            {
                // Do stuff with the removed object
            }
    
            // Call base function
            base.OnVisualChildrenChanged(visualAdded, visualRemoved);
        }
    

    【讨论】:

    【解决方案2】:

    非常 hacky 但对我有用,以防您不从控件继承,因此您无法覆盖 OnVisualChildrenChanged 方法。

    你可以监听 LayoutUpdated 事件。

    在下面的例子中,我想第一次听我的 Grid,名为 GridYouWantToListenTo,添加一个或两个元素:

    <Window x:Class="WpfApplication23.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApplication23"
            mc:Ignorable="d"
            Title="MainWindow" Height="350" Width="525">
        <Grid x:Name="GridYouWantToListenTo">
        </Grid>
    </Window>
    

    后面的代码:

    using System;
    using System.Linq;
    using System.Windows;
    
    namespace WpfApplication23
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
    
                GridYouWantToListenTo.LayoutUpdated += GridYouWantToListenTo_LayoutUpdated;
            }
    
            private int _lastNumbreOfGridChildren = 0;
            private void GridYouWantToListenTo_LayoutUpdated(object sender, EventArgs e)
            {
                var children = GridYouWantToListenTo
                        ?.Children
                        ?.OfType<FrameworkElement>() ?? Enumerable.Empty<FrameworkElement>();
    
                if (!children.Any())
                {
                    _lastNumbreOfGridChildren = 0;
                }
    
                int currentNumberOfItems = children.Count();
    
                if (_lastNumbreOfGridChildren == 0 && currentNumberOfItems == 1)
                {
                    //Your Logic
                }
                else if (_lastNumbreOfGridChildren == 0 && currentNumberOfItems == 2)
                {
                    //Your Logic
                }
            }
        }
    }
    

    【讨论】:

    • LayoutUpdated 有一个不幸的愚蠢之处,它总是将 null 作为发送者传递,因此除非您为每个控件使用唯一的处理程序,否则您无法消除对多个控件的侦听的歧义,这有点荒谬。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-24
    • 2019-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多