【问题标题】:How could I put a border on my grid control in WPF?如何在 WPF 中的网格控件上设置边框?
【发布时间】:2011-02-15 16:36:32
【问题描述】:

如何在 C#/WPF 中的网格上设置边框?

这是我想要的,但在整个事物周围设置了一个边框,而不是我在我的应用程序中放置的网格控件。

<Grid>
    <Border BorderBrush="Black" BorderThickness="2">
        <Grid Height="166" HorizontalAlignment="Left" Margin="12,12,0,0" Name="grid1" VerticalAlignment="Top" Width="479" Background="#FFF2F2F2" />
    </Border>
... and so on ...

【问题讨论】:

  • 你所说的“整体”是什么意思?我怀疑您的网格中还有其他内容-您也许应该发布那是什么。我的怀疑是你有某种数据网格控件以及你的网格容器(这是你在你的样本中放入的,可能包含“整个东西”),这就是产生混淆的地方。

标签: c# wpf


【解决方案1】:

如果你只想要一个外边框,最简单的方法是把它放在一个Border控件中:

<Border BorderBrush="Black" BorderThickness="2">
    <Grid>
       <!-- Grid contents here -->
    </Grid>
</Border>

您看到边框完全填满控件的原因是,默认情况下,它的 Horizo​​ntalAlignment 和 VerticalAlignment 设置为 Stretch。请尝试以下操作:

<Grid>
    <Border  HorizontalAlignment="Left" VerticalAlignment="Top"  BorderBrush="Black" BorderThickness="2">
        <Grid Height="166" HorizontalAlignment="Left" Margin="12,12,0,0" Name="grid1" VerticalAlignment="Top" Width="479" Background="#FFF2F2F2" />
    </Border>
</Grid>

这应该可以满足您的需求(尽管您可能希望在所有 4 个边上都留出边距,而不仅仅是 2...)

【讨论】:

  • 它不能按我的意愿工作......我已经在我的问题中添加了一些代码。
  • @Jason94:我更新了我的答案,向您展示如何获得我认为您所追求的...
  • @ReedCopsey Reed,我知道您的解决方案有效,但我不明白为什么 Border 元素位于 Grid 元素内 - 这不是很反直觉吗?谢谢。
  • @Sabuncu 你会注意到我的原版没有 - 我正在让 OP 的编辑“工作”
  • 这似乎在我的主窗口内部放置了一个边界,而不是在封装在其中的网格外部周围。任何想法为什么?
【解决方案2】:

如果将网格嵌套在边框控件中

<Border>
    <Grid>
    </Grid>
</Border>

没有做你想做的事,那么你将不得不为网格(或边框)制作你自己的控件模板来做你想做的事。

【讨论】:

  • 哦...好吧:D认为我忽略了一个变量或一些花哨的WPF(我是新手:D)
  • 您不能为 Grid 和 Border 创建模板,因为它们没有 Template 属性,因为它们不是从 Control 派生的,而是从 Panel 和 Decorator 派生的。 Reed Copsey has the (pretty simple) solution.
【解决方案3】:

我认为你的问题是边距应该在边框标签中指定,而不是在网格中。

【讨论】:

    【解决方案4】:

    如果将来可能对任何人有用,这是对我有用的稍后答案。我想在网格的所有四个边上都有一个简单的边框,我就这样实现了......

    <DataGrid x:Name="dgDisplay" Margin="5" BorderBrush="#1266a7" BorderThickness="1"...
    

    【讨论】:

    • Grid 控件没有BorderBrush 属性,但DataGrid 有...
    【解决方案5】:
    <Grid x:Name="outerGrid">
        <Grid x:Name="innerGrid">
            <Border BorderBrush="#FF179AC8" BorderThickness="2" />
            <other stuff></other stuff>
            <other stuff></other stuff>
        </Grid>
    </Grid>
    

    此代码在“innerGrid”内包裹一个边框

    【讨论】:

    • 嗨@ElvinMammadov。你能描述更多吗。你有任何错误吗?这段代码对我来说很好。
    • 需要在Border标签中添加Grid.ColumnSpan="你要覆盖的列" Grid.RowSpan="你要覆盖的行"。否则它只覆盖第一个单元格。
    【解决方案6】:

    如果有人对类似问题感兴趣,但没有使用 XAML,这是我的解决方案:

    var B1 = new Border();
    B1.BorderBrush = Brushes.Black;
    B1.BorderThickness = new Thickness(0, 1, 0, 0); // You can specify here which borders do you want
    YourPanel.Children.Add(B1);
    

    【讨论】:

      【解决方案7】:

      这是我的解决方案,希望对你有用:

      public class Sheet : Grid
      {
          public static readonly DependencyProperty BorderBrushProperty = DependencyProperty.Register(nameof(BorderBrush), typeof(Brush), typeof(Sheet), new FrameworkPropertyMetadata(Brushes.Transparent, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnBorderBrushChanged));
      
          public static readonly DependencyProperty BorderThicknessProperty = DependencyProperty.Register(nameof(BorderThickness), typeof(double), typeof(Sheet), new FrameworkPropertyMetadata(1D, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnBorderThicknessChanged, CoerceBorderThickness));
          public static readonly DependencyProperty CellSpacingProperty = DependencyProperty.Register(nameof(CellSpacing), typeof(double), typeof(Sheet), new FrameworkPropertyMetadata(0D, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnCellSpacingChanged, CoerceCellSpacing));
      
          public Brush BorderBrush
          {
              get => this.GetValue(BorderBrushProperty) as Brush;
              set => this.SetValue(BorderBrushProperty, value);
          }
      
          public double BorderThickness
          {
              get => (double)this.GetValue(BorderThicknessProperty);
              set => this.SetValue(BorderThicknessProperty, value);
          }
      
          public double CellSpacing
          {
              get => (double)this.GetValue(CellSpacingProperty);
              set => this.SetValue(CellSpacingProperty, value);
          }
      
          protected override Size ArrangeOverride(Size arrangeSize)
          {
              Size size = base.ArrangeOverride(arrangeSize);
              double border = this.BorderThickness;
              double doubleBorder = border * 2D;
              double spacing = this.CellSpacing;
              double halfSpacing = spacing * 0.5D;
              if (border > 0D || spacing > 0D)
              {
                  foreach (UIElement child in this.InternalChildren)
                  {
                      this.GetChildBounds(child, out double left, out double top, out double width, out double height);
      
                      left += halfSpacing + border;
                      top += halfSpacing + border;
                      height -= spacing + doubleBorder;
                      width -= spacing + doubleBorder;
      
                      if (width < 0D)
                      {
                          width = 0D;
                      }
      
                      if (height < 0D)
                      {
                          height = 0D;
                      }
      
                      left -= left % 0.5D;
                      top -= top % 0.5D;
                      width -= width % 0.5D;
                      height -= height % 0.5D;
      
                      child.Arrange(new Rect(left, top, width, height));
                  }
      
                  if (border > 0D && this.BorderBrush != null)
                  {
                      this.InvalidateVisual();
                  }
              }
      
              return size;
          }
          
          protected override void OnRender(DrawingContext dc)
          {
              base.OnRender(dc);
      
              if (this.BorderThickness > 0D && this.BorderBrush != null)
              {
                  if (this.CellSpacing == 0D)
                  {
                      this.DrawCollapsedBorder(dc);
                  }
                  else
                  {
                      this.DrawSeperatedBorder(dc);
                  }
              }
          }
      
          private void DrawSeperatedBorder(DrawingContext dc)
          {
              double spacing = this.CellSpacing;
              double halfSpacing = spacing * 0.5D;
      
      
              #region draw border
              Pen pen = new Pen(this.BorderBrush, this.BorderThickness);
              UIElementCollection children = this.InternalChildren;
              foreach (UIElement child in children)
              {
                  this.GetChildBounds(child, out double left, out double top, out double width, out double height);
                  left += halfSpacing;
                  top += halfSpacing;
                  width -= spacing;
                  height -= spacing;
      
                  dc.DrawRectangle(null, pen, new Rect(left, top, width, height));
              }
              #endregion
          }
      
          private void DrawCollapsedBorder(DrawingContext dc)
          {
              RowDefinitionCollection rows = this.RowDefinitions;
              ColumnDefinitionCollection columns = this.ColumnDefinitions;
              int rowCount = rows.Count;
              int columnCount = columns.Count;
              const byte BORDER_LEFT = 0x08;
              const byte BORDER_TOP = 0x04;
              const byte BORDER_RIGHT = 0x02;
              const byte BORDER_BOTTOM = 0x01;
              byte[,] borderState = new byte[rowCount, columnCount];
              int column = columnCount - 1;
              int columnSpan;
              int row = rowCount - 1;
              int rowSpan;
              #region generate main border data
              for (int i = 0; i < rowCount; i++)
              {
                  borderState[i, 0] = BORDER_LEFT;
                  borderState[i, column] = BORDER_RIGHT;
              }
      
              for (int i = 0; i < columnCount; i++)
              {
                  borderState[0, i] |= BORDER_TOP;
                  borderState[row, i] |= BORDER_BOTTOM;
              }
              #endregion
      
              #region generate child border data
              UIElementCollection children = this.InternalChildren;
              foreach (UIElement child in children)
              {
                  this.GetChildLayout(child, out row, out rowSpan, out column, out columnSpan);
                  for (int i = 0; i < rowSpan; i++)
                  {
                      borderState[row + i, column] |= BORDER_LEFT;
                      borderState[row + i, column + columnSpan - 1] |= BORDER_RIGHT;
                  }
                  for (int i = 0; i < columnSpan; i++)
                  {
                      borderState[row, column + i] |= BORDER_TOP;
                      borderState[row + rowSpan - 1, column + i] |= BORDER_BOTTOM;
                  }
              }
              #endregion
      
              #region draw border
              Pen pen = new Pen(this.BorderBrush, this.BorderThickness);
              double left;
              double top;
              double width, height;
      
      
              for (int r = 0; r < rowCount; r++)
              {
                  RowDefinition v = rows[r];
                  top = v.Offset;
                  height = v.ActualHeight;
                  for (int c = 0; c < columnCount; c++)
                  {
                      byte state = borderState[r, c];
      
                      ColumnDefinition h = columns[c];
                      left = h.Offset;
                      width = h.ActualWidth;
                      if ((state & BORDER_LEFT) == BORDER_LEFT)
                      {
                          dc.DrawLine(pen, new Point(left, top), new Point(left, top + height));
                      }
                      if ((state & BORDER_TOP) == BORDER_TOP)
                      {
                          dc.DrawLine(pen, new Point(left, top), new Point(left + width, top));
                      }
                      if ((state & BORDER_RIGHT) == BORDER_RIGHT && (c + 1 >= columnCount || (borderState[r, c + 1] & BORDER_LEFT) == 0))
                      {
                          dc.DrawLine(pen, new Point(left + width, top), new Point(left + width, top + height));
                      }
                      if ((state & BORDER_BOTTOM) == BORDER_BOTTOM && (r + 1 >= rowCount || (borderState[r + 1, c] & BORDER_TOP) == 0))
                      {
                          dc.DrawLine(pen, new Point(left, top + height), new Point(left + width, top + height));
                      }
                  }
      
              }
              #endregion
          }
      
          private void GetChildBounds(UIElement child, out double left, out double top, out double width, out double height)
          {
              ColumnDefinitionCollection columns = this.ColumnDefinitions;
              RowDefinitionCollection rows = this.RowDefinitions;
              int rowCount = rows.Count;
      
              int row = (int)child.GetValue(Grid.RowProperty);
              if (row >= rowCount)
              {
                  row = rowCount - 1;
              }
      
              int rowSpan = (int)child.GetValue(Grid.RowSpanProperty);
              if (row + rowSpan > rowCount)
              {
                  rowSpan = rowCount - row;
              }
              int columnCount = columns.Count;
      
              int column = (int)child.GetValue(Grid.ColumnProperty);
              if (column >= columnCount)
              {
                  column = columnCount - 1;
              }
      
              int columnSpan = (int)child.GetValue(Grid.ColumnSpanProperty);
              if (column + columnSpan > columnCount)
              {
                  columnSpan = columnCount - column;
              }
      
              left = columns[column].Offset;
              top = rows[row].Offset;
              ColumnDefinition right = columns[column + columnSpan - 1];
              width = right.Offset + right.ActualWidth - left;
              RowDefinition bottom = rows[row + rowSpan - 1];
              height = bottom.Offset + bottom.ActualHeight - top;
              if (width < 0D)
              {
                  width = 0D;
              }
      
              if (height < 0D)
              {
                  height = 0D;
              }
      
          }
          private void GetChildLayout(UIElement child, out int row, out int rowSpan, out int column, out int columnSpan)
          {
              int rowCount = this.RowDefinitions.Count;
      
              row = (int)child.GetValue(Grid.RowProperty);
              if (row >= rowCount)
              {
                  row = rowCount - 1;
              }
      
              rowSpan = (int)child.GetValue(Grid.RowSpanProperty);
              if (row + rowSpan > rowCount)
              {
                  rowSpan = rowCount - row;
              }
              int columnCount = this.ColumnDefinitions.Count;
      
              column = (int)child.GetValue(Grid.ColumnProperty);
              if (column >= columnCount)
              {
                  column = columnCount - 1;
              }
      
              columnSpan = (int)child.GetValue(Grid.ColumnSpanProperty);
              if (column + columnSpan > columnCount)
              {
                  columnSpan = columnCount - column;
              }
          }
      
          private static void OnBorderBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
          {
              if (d is UIElement element)
              {
                  element.InvalidateVisual();
              }
          }
      
          private static void OnBorderThicknessChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
          {
              if (d is UIElement element)
              {
                  element.InvalidateArrange();
              }
          }
      
          private static void OnCellSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
          {
              if (d is UIElement element)
              {
                  element.InvalidateArrange();
              }
          }
      
          private static object CoerceBorderThickness(DependencyObject d, object baseValue)
          {
              if (baseValue is double value)
              {
                  return value < 0D || double.IsNaN(value) || double.IsInfinity(value) ? 0D : value;
              }
      
              return 0D;
          }
          private static object CoerceCellSpacing(DependencyObject d, object baseValue)
          {
              if (baseValue is double value)
              {
                  return value < 0D || double.IsNaN(value) || double.IsInfinity(value) ? 0D : value;
              }
      
              return 0D;
          }
      }
      

      演示:

      【讨论】:

      • 感谢分享!有没有可能添加像 CellPadding 这样的东西?
      • 可以修改ArrangeOverride
      猜你喜欢
      • 2023-03-28
      • 2011-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-19
      • 2015-12-12
      • 2017-05-11
      • 2013-06-22
      相关资源
      最近更新 更多