简体   繁体   中英

How to set DP value when the custom control use in the xaml? (when declaring)

My English skill is poor because I'm not a native English speaker. I hope you to understand.

I created a custom window that overrides the title bar shape. The part of the xaml code is as shown below.

<Style x:Key="MainWindow" TargetType="{x:Type Window}">
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}" />
        <Setter Property="WindowStyle" Value="None"/>
        <Setter Property="AllowsTransparency" Value="True"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Window}">
                    <Grid>
                         <Border x:Name="PART_TITLEBAR"
                                 Margin="2,0,2,2"
                                 Height="30"
                                 DockPanel.Dock="Top"
                                 CornerRadius="2"
                                 Background="Transparent">

This control works well except for one problem. The problem is that can't set the value of the DP. The part of the cs code of the control is as shown below.

[TemplatePart(Name = "PART_TITLEBAR", Type = typeof(UIElement))]
public partial class CustomWindow : Window
{
    private UIElement TitleBar { get; set; }

    #region Dependency Properties for appearance.
    public int TitleBarHeight
    {
        get { return (int)GetValue(TitleBarHeightProperty); }
        set { SetValue(TitleBarHeightProperty, value); }
    }

    // Using a DependencyProperty as the backing store for TitleBarHeight.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TitleBarHeightProperty =
        DependencyProperty.Register("TitleBarHeight", typeof(int), typeof(CustomWindow), new PropertyMetadata(TitleBarHeightChanged));

    public static void TitleBarHeightChanged(DependencyObject dp, DependencyPropertyChangedEventArgs args)
    {
        CustomWindow window = dp as CustomWindow;

        Border titleBar = window.TitleBar as Border;
        if (titleBar == null) return;

        titleBar.Height = (int)args.NewValue;
    }



    public SolidColorBrush TitleTextBrush
    {
        get { return (SolidColorBrush)GetValue(TitleTextBrushProperty); }
        set { SetValue(TitleTextBrushProperty, value); }
    }

    // Using a DependencyProperty as the backing store for TitleTextBrush.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TitleTextBrushProperty =
        DependencyProperty.Register("TitleTextBrush", typeof(SolidColorBrush), typeof(CustomWindow), new PropertyMetadata(TitleTextBrushChanged));

    public static void TitleTextBrushChanged(DependencyObject dp, DependencyPropertyChangedEventArgs args)
    {
        CustomWindow window = dp as CustomWindow;

        Border titleBar = window.TitleBar as Border;
        if (titleBar == null) return;

        // find the textblock control of the children of the titlebar and change the value of the foreground of the control.
    }
    #endregion

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        AttachToVisualTree();
    }

    private void AttachToVisualTree()
    {
        AttachCloseButton();
        AttachMinimizeButton();
        AttachMaximizeRestoreButton();
        AttachTitleBar();
        AttachBorders();
    }

    private void AttachTitleBar()
    {
        if (TitleBar != null)
        {
            TitleBar.RemoveHandler(UIElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler(OnTitlebarClick));
        }

        UIElement titleBar = GetChildControl<UIElement>("PART_TITLEBAR");
        if (titleBar != null)
        {
            TitleBar = titleBar;
            titleBar.AddHandler(UIElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler(OnTitlebarClick));
        }
    }

I tried to track the problem and I have found the cause. First, I loaded the custom control in the main project and set the value of the DP on the custom control as below.

<custom:CustomWindow TitleBarHeight="20">
    <.../>
</custom:CustomWindow>

And then later, I executed the project and the sequence processed as below.

  1. The CustomWindow is created. (constructor called)
  2. The TitleBarHeight value of the CustomWindow is set
  3. OnApplyTemplate() of the CustomWindow is called.

According to my confirmation, sequence 2 is the starting point of the problem.

In sequence 2, WPF trying to set the TitleBarHeight value of the CustomWindow. therefore the below code is called.

public static void TitleBarHeightChanged(DependencyObject dp, DependencyPropertyChangedEventArgs args)
{
    CustomWindow window = dp as CustomWindow;

    Border titleBar = window.TitleBar as Border;
    if (titleBar == null) return;

    titleBar.Height = (int)args.NewValue;
}

But at this point, the TitleBar has not be instantiated so TitleBarHeight value is not set. As a result, it would be moved to the routine of the below.

if (titleBar == null) return;

After then later, OnApplyTemplate() is called and TitleBar is instantiated.

Summary : when execute < custom:CustomWindow TitleBarHeight="20"> logic, at this point the TitleBar of the CustomWindow is not instantiated so TitleBarHeight value is not set.

What I should do to solve this problem? I hope to get your help.

Thank you for reading.

Thanks for the advice, I solved this problem.

I modified xaml code as below.

<Border x:Name="PART_TITLEBAR"
        Margin="2,0,2,2"
        Height="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:CustomWindow}, Path=TitleBarHeight}"
        DockPanel.Dock="Top"
        CornerRadius="2"
        Background="Transparent">

If you have a better way of doing this, please let me know.

Thank you for advice.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM