I create a "custom control" in WinUI3 project:
public sealed class BINPersonPicture2 : Control
{
public ImageSource PortraitUrl
{
get => (ImageSource)GetValue(PortraitUrlProperty);
set => SetValue(PortraitUrlProperty, value);
}
public string PersonName
{
get => (string)GetValue(PersonNameProperty);
set => SetValue(PersonNameProperty, value);
}
DependencyProperty PortraitUrlProperty = DependencyProperty.Register(nameof(PortraitUrl),typeof(ImageSource),typeof(BINPersonPicture2),new PropertyMetadata(default(string), new PropertyChangedCallback(OnPortraitUrlChanged)));
DependencyProperty PersonNameProperty = DependencyProperty.Register(nameof(PersonName), typeof(string), typeof(BINPersonPicture2), new PropertyMetadata(default(string), new PropertyChangedCallback(OnPersonNameChanged)));
public BINPersonPicture2()
{
this.DefaultStyleKey = typeof(BINPersonPicture2);
}
private static void OnPortraitUrlChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
BINPersonPicture2 labelControl = d as BINPersonPicture2; //null checks omitted
if(e.NewValue is BitmapImage bm)
{
Debug.WriteLine($"bm.PixelWidth:{bm.PixelWidth}");
//If image load failed, it seems that image width is zero, but how to apply on default image on it?
//I try this but it will cause stack overflow...
if (bm.PixelWidth == 0)
{
labelControl.PortraitUrl = new BitmapImage(new Uri("ms-appx:///Assets/portrait.jpg"));
}
else
{
labelControl.PortraitUrl = bm;
}
}
}
private static void OnPersonNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
BINPersonPicture2 labelControl = d as BINPersonPicture2; //null checks omitted
String s = e.NewValue as String; //null checks omitted
labelControl.PersonName = s;
}
}
The xaml is:
<Style TargetType="local:BINPersonPicture2" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:BINPersonPicture2">
<Grid HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Ellipse Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
<Ellipse.Fill>
<ImageBrush x:Name="portraitBrush" ImageSource="{TemplateBinding PortraitUrl}"/>
</Ellipse.Fill>
</Ellipse>
<TextBlock Text="{TemplateBinding PersonName}" FontSize="14" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I want to replace the picture to default when the PortraitUrl image load failed(or hide the Ellipse control)
I tried set PortraitUrl property in OnPortraitUrlChanged, but it will cause crash(System.StackOverflowException)....