WPF - Как определить, когда добавляются новые дочерние элементы Visual? - PullRequest
7 голосов
/ 17 мая 2011

Исходя из некоторых пользовательских настроек безопасности, я изменяю дочерние элементы управления окна только на чтение и отключаю.Для этого я запускаю дочерние элементы управления при загрузке окна.

Это работает просто отлично.На 99% идеально.

В моем окне у меня есть ItemsControl, содержимое которого основано на ComboBox.Измените ComboBox, дочерние элементы управления ItemsControl снова привязаны к данным.Но тогда безопасность (только чтение / отключено) больше не соответствует действительности.

Прежде чем перейти к решению, я знаю, что смогу обработать событие ComboBox Change;но у меня есть много таких блоков, и я не могу применить универсальное решение на уровне окна (думаю: база), независимо от того, что мои разработчики добавляют в окно / форму.

Мой вопрос (извините за долгоВвод), как я могу определить, когда новый дочерний элемент добавляется в окно из-за некоторой динамической активности, например привязки данных?Есть ли событие NewChildAdded?Есть ли событие DataBindingJustChangedThings?

Должно быть что-то.

Если ваше решение включает таймер, вам не нужно отвечать.Мои формы слишком сложны, чтобы справиться с этой дополнительной нагрузкой - и задержка между тиками слишком реальна из-за проблем безопасности.

Вы можете подумать, просто сделайте внешний контейнер доступным только для чтения или отключенным.Но это негативно влияет на такие вещи, как расширители, многострочные текстовые поля и списки.Такой подход не является достаточно зернистым.Конечно, именно здесь мы начали итерации назад.

Если ваше решение включает стиль, вам нужно указать, как я могу переопределить ваш подход для каждого элемента управления.Некоторые элементы управления (например, флажок) нельзя отключить, поскольку они имеют назначение в макете пользовательского интерфейса.

Извините за ограничения, но я планирую использовать решение в производстве.

Спасибо.

Ответы [ 2 ]

19 голосов
/ 17 мая 2011

Вы пробовали 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);
    }
4 голосов
/ 27 ноября 2016

Очень хакерский, но сработал для меня, если вы не наследуете от элемента управления и не можете переопределить метод OnVisualChildrenChanged .

Вы можете прослушать событие LayoutUpdated.

В приведенном ниже примере я хочу прослушать, когда моя Сетка, названная 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
            }
        }
    }
}
...