❔ WPF Cannot find child when it's there
Hi!
I am working on my own RoundedCorners attachedproperty however I have stumbled upon a problem
Problem: When an item that starts invisible goes visible the effect is not applied
I've tried experimenting with Loaded and IsVisibleChanged events, where IsVisibleChanged actually fires on the visibility change and the Loaded fires on the start
But when IsVisibleChanged fires there are still no children detected in a tree to even try to look for a border
3 Replies
public static class RoundedCorners {
public static readonly DependencyProperty RadiusProperty = DependencyProperty.RegisterAttached(
"Radius",
typeof(CornerRadius),
typeof(RoundedCorners),
new PropertyMetadata(default(CornerRadius), RadiusChanged));
public static void SetRadius(DependencyObject element, CornerRadius value) {
element.SetValue(RadiusProperty, value);
}
public static CornerRadius GetRadius(DependencyObject element) {
return (CornerRadius)element.GetValue(RadiusProperty);
}
public static void RadiusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
Border? border = d as Border;
if (border == null) {
border = UIHelper.FindChild<Border>(d);
}
if (border == null) {
InitialRadiusSet(d, e);
return;
}
border.CornerRadius = (CornerRadius)e.NewValue;
}
private static void InitialRadiusSet(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var element = d as Control;
if (element == null) return;
element.Loaded -= LoadedHandler;
element.Loaded += LoadedHandler;
}
private static void LoadedHandler(object sender, RoutedEventArgs e) {
var element = sender as Control;
if (element == null) return;
var border = UIHelper.FindChild<Border>(element);
if (border == null) return;
var radius = GetRadius(element);
border.CornerRadius = radius;
}
}
public static class RoundedCorners {
public static readonly DependencyProperty RadiusProperty = DependencyProperty.RegisterAttached(
"Radius",
typeof(CornerRadius),
typeof(RoundedCorners),
new PropertyMetadata(default(CornerRadius), RadiusChanged));
public static void SetRadius(DependencyObject element, CornerRadius value) {
element.SetValue(RadiusProperty, value);
}
public static CornerRadius GetRadius(DependencyObject element) {
return (CornerRadius)element.GetValue(RadiusProperty);
}
public static void RadiusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
Border? border = d as Border;
if (border == null) {
border = UIHelper.FindChild<Border>(d);
}
if (border == null) {
InitialRadiusSet(d, e);
return;
}
border.CornerRadius = (CornerRadius)e.NewValue;
}
private static void InitialRadiusSet(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var element = d as Control;
if (element == null) return;
element.Loaded -= LoadedHandler;
element.Loaded += LoadedHandler;
}
private static void LoadedHandler(object sender, RoutedEventArgs e) {
var element = sender as Control;
if (element == null) return;
var border = UIHelper.FindChild<Border>(element);
if (border == null) return;
var radius = GetRadius(element);
border.CornerRadius = radius;
}
}
//one of few sample dependency properties
public static readonly DependencyProperty TopLeftProperty = DependencyProperty.RegisterAttached(
"TopLeft",
typeof(double),
typeof(RoundedCorners),
new PropertyMetadata(default(double), TopLeftChanged));
public static void SetTopLeft(DependencyObject element, double value) {
element.SetValue(TopLeftProperty, value);
}
public static double GetTopLeft(DependencyObject element) {
return (double)element.GetValue(TopLeftProperty);
}
private static void TopLeftChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var cornerRadius = GetRadius(d);
cornerRadius.TopLeft = (double)e.NewValue;
SetRadius(d, cornerRadius);
}
//one of few sample dependency properties
public static readonly DependencyProperty TopLeftProperty = DependencyProperty.RegisterAttached(
"TopLeft",
typeof(double),
typeof(RoundedCorners),
new PropertyMetadata(default(double), TopLeftChanged));
public static void SetTopLeft(DependencyObject element, double value) {
element.SetValue(TopLeftProperty, value);
}
public static double GetTopLeft(DependencyObject element) {
return (double)element.GetValue(TopLeftProperty);
}
private static void TopLeftChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var cornerRadius = GetRadius(d);
cornerRadius.TopLeft = (double)e.NewValue;
SetRadius(d, cornerRadius);
}
______
this code handles initial loading in items and then reloading them
private static void InitialRadiusSet(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var element = d as Control;
if (element == null) return;
element.Loaded -= LoadedHandler;
element.Loaded += LoadedHandler;
}
private static void LoadedHandler(object sender, RoutedEventArgs e) {
var element = sender as Control;
if (element == null) return;
var border = UIHelper.FindChild<Border>(element);
if (border == null) return;
var radius = GetRadius(element);
border.CornerRadius = radius;
}
private static void InitialRadiusSet(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var element = d as Control;
if (element == null) return;
element.Loaded -= LoadedHandler;
element.Loaded += LoadedHandler;
}
private static void LoadedHandler(object sender, RoutedEventArgs e) {
var element = sender as Control;
if (element == null) return;
var border = UIHelper.FindChild<Border>(element);
if (border == null) return;
var radius = GetRadius(element);
border.CornerRadius = radius;
}
element.Loaded -= LoadedHandler;
element.Loaded += LoadedHandler;
element.Loaded -= LoadedHandler;
element.Loaded += LoadedHandler;
_______
offending code:
<Button
Width="40"
Height="40"
Margin="10"
attached:RoundedCorners.Radius="{StaticResource RoundedSmRadius}"
Background="{StaticResource BrushBgOverlay}"
BorderThickness="0"
Command="{Binding ConfirmTitleCommand}">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
<Button
Width="40"
Height="40"
Margin="10"
attached:RoundedCorners.Radius="{StaticResource RoundedSmRadius}"
Background="{StaticResource BrushBgOverlay}"
BorderThickness="0"
Command="{Binding ConfirmTitleCommand}">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
public static T? FindChild<T>(DependencyObject parent)
where T : DependencyObject {
if (parent == null) return null;
T? foundChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++) {
var child = VisualTreeHelper.GetChild(parent, i);
T? childType = child as T;
if (childType != null) {
foundChild = (T)child;
break;
}
foundChild = FindChild<T>(child);
if (foundChild != null) break;
}
return foundChild;
}
public static T? FindChild<T>(DependencyObject parent)
where T : DependencyObject {
if (parent == null) return null;
T? foundChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++) {
var child = VisualTreeHelper.GetChild(parent, i);
T? childType = child as T;
if (childType != null) {
foundChild = (T)child;
break;
}
foundChild = FindChild<T>(child);
if (foundChild != null) break;
}
return foundChild;
}
Items that are invisible or disabled will not participate in events.
What are you trying to do specifically?
I use a recursive method to find a parent for something in WPF
Was this issue resolved? If so, run
/close
- otherwise I will mark this as stale and this post will be archived until there is new activity.