Based on some custom security settings, I alter window child controls to readonly and disabled. To accomplish this, I loop through child controls when the window loads.
This works just fine. 99% perfect.
In my window I have an ItemsControl whose content is based on a ComboBox. Change the ComboBox, the child controls in the ItemsControl are databound again. But, then security (readonly/disabled) is no longer true.
Before you jump to the solution, I know I could handle the ComboBox changed event; but, I have many such boxes and wnt a generic solution to can apply at the window-level (think: base) no matter what my developers add to the window/form.
My question (sorry for the long lead in) is, how can I detect when a new child is added to the window because of some dynamic activity like databinding? Is there a NewChildAdded event? Is there a DataBindingJustChangedThings event?
There's gotta be something.
If your solution includes a timer, you need not reply. My forms are too complex to handle that extra load - and the delay between ticks is too real of a security issue.
You might be thinking, just make the outer-container readonly or disabled. But this has a negative effect on things like expanders, multi-line textboxes and listboxes. Such an approach is not grainular enough. Of course, it is where we started iterations ago.
If your solution includes a style, you need to include how I can override your approach on a per-control basis. Some controls (like a checkbox) cannot be disabled as they have a purpose in the UI layout.
Sorry for the constraints, but I plan to use the solution in production.
Thank you.
Have you tried 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);
}
Very hacky but worked for me, in case you don't inherit from the control so you can't override the OnVisualChildrenChanged method.
You can listen to LayoutUpdated event.
On the example bellow, I want to listen to the first time my Grid, named GridYouWantToListenTo, add one or two elements:
<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>
Code behind:
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
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With