Search code examples
xamlmarginuwp-xamlconditional-formatting

Conditional margining for a grid elements in xaml


I have a grid with 2 rows and 4 columns with width and height as specified below. Second row has only one control in col=1 and that control may or may not present(due to some logic).

          <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="*"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions></Grid>

When control is not present:

Since second row is height is "Auto" and when I have no control, I'll have only single row. In that case, I need to have specific margin with respect to grid bottom. Hence, Margin of row 0 control = "0,0,0,14"

When control is present:

When control is present, I have two rows and I need to have margin between two row elements as 6px and second row margin should be 14 w.r.t bottom of grid. Hence, Margin of row 0 control = "0,0,0,6" and Margin of row 1 control = "0,0,0,14"

How could I achieve these different margin values based on second row presence. Please help. Thanks in advance. Refer img:

Grid image


Solution

  • For your requirement, you could use MarginConverter to set row 0 control margin base on the row 1 control's present or not.

    For example

    public class MarginConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            Thickness newMargin;
            var visibility = (Visibility)value;
            switch (visibility)
            {
                case Visibility.Visible:
                    newMargin = new Thickness(0, 0, 0, 6);
    
                    break;
                case Visibility.Collapsed:
                    newMargin = new Thickness(0, 0, 0, 14);
                    break;
                default:
                    break;
            }
            return newMargin;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }
    

    Usage

     <Page.Resources>
         <local:MarginConverter x:Key="Conveter" />
     </Page.Resources>
     <Grid>
         <Grid.RowDefinitions>
             <RowDefinition Height="*" />
             <RowDefinition Height="Auto" />
         </Grid.RowDefinitions>
         <Grid.ColumnDefinitions>
             <ColumnDefinition Width="Auto" />
             <ColumnDefinition Width="*" />
             <ColumnDefinition Width="Auto" />
             <ColumnDefinition Width="*" />
         </Grid.ColumnDefinitions>
         <Rectangle
             Grid.Row="0"
             Grid.Column="1"
             Margin="{Binding ElementName=Row1Control, Path=Visibility, Converter={StaticResource Conveter}}"
             Fill="Red" />
         <Rectangle
             x:Name="Row1Control"
             Grid.Row="1"
             Grid.Column="1"
             Height="80"
             Margin="0,0,0,14"
             Fill="Black"
             Visibility="Visible" />
     </Grid>
    

    Update

    But in my case, Row1Control is dynamically set in the backend.

    you could detect RootGrid LayoutUpdated event, if you add the control it will be invoked, then re-set MarginProperty in the following method.

    private int oldCount;
    private void RootGrid_LayoutUpdated(object sender, object e)
    {
       
        if(RootGrid.Children.Count > oldCount)
        {
            if (RootGrid.Children.Any(p => p.GetValue(NameProperty).ToString() == "Row1Control"))
            {
                Row0Control.SetValue(MarginProperty, new Thickness(0, 0, 0, 6));
            }
            else
            {
                Row0Control.SetValue(MarginProperty, new Thickness(0, 0, 0, 14));
            }
            oldCount = RootGrid.Children.Count;
        }         
       
    }
    

    Add element in the code behind.

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        var Row1Control = new Rectangle() { Height = 80, Margin = new Thickness(0, 0, 0, 14), Fill = new SolidColorBrush(Colors.Black), Name = "Row1Control" };
        Row1Control.SetValue(Grid.ColumnProperty, 1);
        Row1Control.SetValue(Grid.RowProperty, 1);
        RootGrid.Children.Add(Row1Control);
    
    }