Search code examples
c#wpfxamluser-controlsrowdefinition

Different specification of WPF grid row sizes of the same user control depending of situation


I have done reusable user control which is used few times in my project.

Usually the second row of the main grid needs to be 7 times bigger than first one, but in a particular situation it needs to be just 5 times bigger.

<Grid x:Name="mainGrid">    
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="7*"/>
    </Grid.RowDefinitions>
    ...
</Grid>

I tried to set it through XAML:

<helperControls:AttachmentsGridControl x:Name="projectAttachmentsControl" ... HeightOfSecondRow="5" />

and in .cs part:

public int HeightOfSecondRow { get; set; }
public AttachmentsGridControl()
{
    InitializeComponent();
    if(HeightOfSecondRow > 0)
        this.mainGrid.RowDefinitions[1].Height = new GridLength(HeightOfSecondRow, GridUnitType.Star);
}

But the value is not passed while constructors of controls are called. The value needs to be passed on a time when constructor is called, so I can specify how much the height of the second row needs to be and render it properly.


Solution

  • Instead of overwriting the HeightOfSecondRow in the constructor, make it a dependency property of type GridLength with a default value of 7*. The coerce value callback will ensure that a value that is set in XAML or bound with a binding will be positive, otherwise it will be replaced with the default value.

    public partial class AttachmentsGridControl : UserControl
    {
       public static readonly DependencyProperty HeightOfSecondRowProperty = DependencyProperty.Register(
          nameof(HeightOfSecondRow), typeof(GridLength), typeof(AttachmentsGridControl),
          new PropertyMetadata(new GridLength(7, GridUnitType.Star), null, OnCoerceValue));
    
       public GridLength HeightOfSecondRow
       {
          get => (GridLength)GetValue(HeightOfSecondRowProperty);
          set => SetValue(HeightOfSecondRowProperty, value);
       }
    
       public AttachmentsGridControl()
       {
          InitializeComponent();
       }
    
       private static object OnCoerceValue(DependencyObject d, object value)
       {
          var gridLength = (GridLength)value;
          return gridLength.Value > 0.0 ? gridLength : HeightOfSecondRowProperty.GetMetadata(d).DefaultValue;
       }
    }
    

    Adapt the binding of Height to use the HeightOfSecondRow property of your AttachmentsGridControl.

    <Grid x:Name="mainGrid">
       <Grid.RowDefinitions>
          <RowDefinition Height="*"/>
          <RowDefinition Height="{Binding HeightOfSecondRow, RelativeSource={RelativeSource AncestorType={x:Type local:AttachmentsGridControl}}}"/>
       </Grid.RowDefinitions>
       <!-- ...your content. -->
    </Grid>
    

    Then you can set the HeightOfSecondRow as before. If you do not set it, the default value will be used.

    <local:AttachmentsGridControl x:Name="projectAttachmentsControl" HeightOfSecondRow="20*"/>