WPF Grid에서 행 또는 열에 대한 여백 및 / 또는 패딩을 쉽게 지정할 수 있습니까?
물론 공간을 넓히기 위해 여분의 열을 추가 할 수는 있지만 패딩 / 여백 작업처럼 보입니다 ( XAML이 훨씬 간단합니다). 이 기능을 추가하기 위해 표준 그리드에서 파생 된 사람이 있습니까?
WPF Grid에서 행 또는 열에 대한 여백 및 / 또는 패딩을 쉽게 지정할 수 있습니까?
물론 공간을 넓히기 위해 여분의 열을 추가 할 수는 있지만 패딩 / 여백 작업처럼 보입니다 ( XAML이 훨씬 간단합니다). 이 기능을 추가하기 위해 표준 그리드에서 파생 된 사람이 있습니까?
답변:
GridWithMargin
에서 상속받은 자신의 클래스를 작성 Grid
하고 ArrangeOverride
메소드를 재정 의하여 여백을 적용 할 수 있습니다
RowDefinition
및 ColumnDefinition
유형입니다 ContentElement
, 그리고 Margin
엄격입니다 FrameworkElement
속성입니다. 당신의 질문에 "쉽게 가능하다" 라는 대답은 가장 확실한 대답이 아닙니다. 그리고 아니요, 이런 종류의 기능을 보여주는 레이아웃 패널을 보지 못했습니다.
제안한대로 추가 행이나 열을 추가 할 수 있습니다. 그러나 Grid
요소 자체 또는에 들어갈 항목 에 여백을 설정할 수도 Grid
있으므로 지금은 가장 좋은 해결 방법입니다.
유스 Border
셀 제어 외부 제어하고 그것을 위해 패딩을 정의합니다 :
<Grid>
<Grid.Resources >
<Style TargetType="Border" >
<Setter Property="Padding" Value="5,5,5,5" />
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border Grid.Row="0" Grid.Column="0">
<YourGridControls/>
</Border>
<Border Grid.Row="1" Grid.Column="0">
<YourGridControls/>
</Border>
</Grid>
출처:
다음과 같은 것을 사용할 수 있습니다.
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Padding" Value="4" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border Padding="{TemplateBinding Padding}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
또는 TemplateBindings가 필요하지 않은 경우 :
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border Padding="4">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
아무도 이것을 언급하지 않았기 때문에 내 솔루션을 추가 할 것이라고 생각했습니다. 그리드를 기반으로 UserControl을 디자인하는 대신 스타일 선언으로 그리드에 포함 된 컨트롤을 대상으로 지정할 수 있습니다. 번거롭고 노동 집약적 인 각 요소에 대해 정의하지 않고도 모든 요소에 패딩 / 여백을 추가하는 것을 처리합니다. 예를 들어, Grid에 TextBlocks 만 포함되어 있으면 다음과 같이 할 수 있습니다.
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="10"/>
</Style>
"셀 패딩"과 같습니다.
Margin
속성이 일어나고, 그것은 모든 것을의 Style
A의가 ResourceDictionary
자사의 모든 요소에 적용되는 TargetType
모든 곳에서 전체 범위 내에서 그 사전의 소유자 요소는. 그래서 그것은 Style
재산이 아니라 그 세류입니다.
이것은 그리 어렵지 않습니다. 2009 년에 질문을 받았을 때 얼마나 어려웠는지 말할 수는 없었습니다.
이 솔루션을 사용할 때 그리드의 하위에 직접 여백을 직접 설정하면 해당 여백은 디자이너에는 나타나지만 런타임에는 나타나지 않습니다.
이 속성은 Grid, StackPanel, WrapPanel, UniformGrid 또는 기타 Panel의 자손에 적용 할 수 있습니다. 즉각적인 어린이에게 영향을 미칩니다. 아이들은 자신의 컨텐츠의 레이아웃을 관리하기를 원할 것으로 추정됩니다.
PanelExt.cs
public static class PanelExt
{
public static Thickness? GetChildMargin(Panel obj)
{
return (Thickness?)obj.GetValue(ChildMarginProperty);
}
public static void SetChildMargin(Panel obj, Thickness? value)
{
obj.SetValue(ChildMarginProperty, value);
}
/// <summary>
/// Apply a fixed margin to all direct children of the Panel, overriding all other margins.
/// Panel descendants include Grid, StackPanel, WrapPanel, and UniformGrid
/// </summary>
public static readonly DependencyProperty ChildMarginProperty =
DependencyProperty.RegisterAttached("ChildMargin", typeof(Thickness?), typeof(PanelExt),
new PropertyMetadata(null, ChildMargin_PropertyChanged));
private static void ChildMargin_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var target = d as Panel;
target.Loaded += (s, e2) => ApplyChildMargin(target, (Thickness?)e.NewValue);
ApplyChildMargin(target, (Thickness?)e.NewValue);
}
public static void ApplyChildMargin(Panel panel, Thickness? margin)
{
int count = VisualTreeHelper.GetChildrenCount(panel);
object value = margin.HasValue ? margin.Value : DependencyProperty.UnsetValue;
for (var i = 0; i < count; ++i)
{
var child = VisualTreeHelper.GetChild(panel, i) as FrameworkElement;
if (child != null)
{
child.SetValue(FrameworkElement.MarginProperty, value);
}
}
}
}
데모:
MainWindow.xaml
<Grid
local:PanelExt.ChildMargin="2"
x:Name="MainGrid"
>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Rectangle Width="100" Height="40" Fill="Red" Grid.Row="0" Grid.Column="0" />
<Rectangle Width="100" Height="40" Fill="Green" Grid.Row="1" Grid.Column="0" />
<Rectangle Width="100" Height="40" Fill="Blue" Grid.Row="1" Grid.Column="1" />
<Button Grid.Row="2" Grid.Column="0" Click="NoMarginClick">No Margin</Button>
<Button Grid.Row="2" Grid.Column="1" Click="BigMarginClick">Big Margin</Button>
<ComboBox Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" />
</Grid>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void NoMarginClick(object sender, RoutedEventArgs e)
{
// In real life, if we wanted to change PanelExt.ChildMargin at runtime, we
// would prefer to bind it to something, probably a dependency property of
// the view. But this will do for a demonstration.
PanelExt.SetChildMargin(MainGrid, null);
}
private void BigMarginClick(object sender, RoutedEventArgs e)
{
PanelExt.SetChildMargin(MainGrid, new Thickness(20));
}
}
build
또는 필요 run
하기 때문에 dw가 있습니까? 좋고 간단한 것. 1 위로
최근에 일부 소프트웨어를 개발하는 동안이 문제가 발생했는데 왜 그런지 묻습니다. 그들이 왜 이런 짓을했는지 ... 정답이 바로 저 앞에있었습니다. 데이터 행은 객체이므로 객체 방향을 유지하는 경우 특정 행의 디자인을 분리해야합니다 (나중에 행 표시를 다시 사용해야한다고 가정). 그래서 대부분의 데이터 디스플레이에 데이터 바인딩 스택 패널과 사용자 지정 컨트롤을 사용하기 시작했습니다. 목록이 간헐적으로 나타나지만 주로 그리드는 기본 페이지 구성 (헤더, 메뉴 영역, 컨텐츠 영역, 기타 영역)에만 사용되었습니다. 사용자 정의 객체는 스택 패널 또는 그리드 내의 각 행에 대한 간격 요구 사항을 쉽게 관리 할 수 있습니다 (단일 그리드 셀은 전체 행 객체를 포함 할 수 있음).
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<custom:MyRowObject Style="YourStyleHereOrGeneralSetter" Grid.Row="0" />
<custom:MyRowObject Style="YourStyleHere" Grid.Row="1" />
</Grid>
또는
<StackPanel>
<custom:MyRowObject Style="YourStyleHere" Grid.Row="0" />
<custom:MyRowObject Style="YourStyleHere" Grid.Row="1" />
</StackPanel>
데이터 바인딩을 사용하는 경우이 접근 방식에서 개인적으로 가장 좋아하는 이점 인 경우 사용자 지정 컨트롤도 DataContext를 상속합니다.
ListView
것은 GridView
모드 에서 WPF 컨트롤 의 조잡한 버전 을 만드는 것이지만 모든“RowObjects”를 동일한 열 너비로 공유 할 수는 없습니다. 실제로는 더 이상 Grid와 관련이 없습니다.
uwp에서 (Windows10FallCreatorsUpdate 버전 이상)
<Grid RowSpacing="3" ColumnSpacing="3">
Xamarin.Forms
.
나는 지금 내 그리드 중 하나를 사용하여 그것을했습니다.
하나의 가능성은 찾고있는 패딩 / 여백으로 작동하도록 고정 너비 행과 열을 추가하는 것입니다.
컨테이너의 크기에 의해 제약을받으며 격자가 포함하는 요소 나 지정된 너비와 높이만큼 커질 수 있습니다. 너비 나 높이가 설정되지 않은 열과 행을 간단히 사용할 수 있습니다. 이렇게하면 그리드 내의 전체 공간이 균등하게 분할됩니다. 그런 다음 그리드 내에서 요소를 세로 및 가로로 가운데에 맞추는 것이 중요합니다.
다른 방법은 모든 그리드 요소를 고정 된 크기와 여백을 가진 단일 행 및 열 그리드로 고정하는 것입니다. 그리드에는 실제 요소를 포함하는 고정 너비 / 높이 상자가 포함되어 있습니다.
최근에 두 개의 열 그리드에서 비슷한 문제가 발생했습니다. 오른쪽 열의 요소에만 여백이 필요했습니다. 두 열의 모든 요소는 TextBlock 유형이었습니다.
<Grid.Resources>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource OurLabelStyle}">
<Style.Triggers>
<Trigger Property="Grid.Column" Value="1">
<Setter Property="Margin" Value="20,0" />
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
이전에 언급했듯이 GridWithMargins 클래스를 만듭니다. 다음은 작업 코드 예제입니다.
public class GridWithMargins : Grid
{
public Thickness RowMargin { get; set; } = new Thickness(10, 10, 10, 10);
protected override Size ArrangeOverride(Size arrangeSize)
{
var basesize = base.ArrangeOverride(arrangeSize);
foreach (UIElement child in InternalChildren)
{
var pos = GetPosition(child);
pos.X += RowMargin.Left;
pos.Y += RowMargin.Top;
var actual = child.RenderSize;
actual.Width -= (RowMargin.Left + RowMargin.Right);
actual.Height -= (RowMargin.Top + RowMargin.Bottom);
var rec = new Rect(pos, actual);
child.Arrange(rec);
}
return arrangeSize;
}
private Point GetPosition(Visual element)
{
var posTransForm = element.TransformToAncestor(this);
var areaTransForm = posTransForm.Transform(new Point(0, 0));
return areaTransForm;
}
}
용법:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:GridWithMargins ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Rectangle Fill="Red" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<Rectangle Fill="Green" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<Rectangle Fill="Blue" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</local:GridWithMargins>
</Grid>
</Window>
이 솔루션이 아직 게시되지 않은 것에 놀랐습니다.
웹에서 시작하면 부트 스트랩과 같은 프레임 워크는 음수 여백을 사용하여 행 / 열을 뒤로 당깁니다.
그것은 조금 장황 할 수도 있지만 (나쁘지는 않지만) 작동하며 요소의 간격과 크기가 균등합니다.
아래 예에서는 StackPanel
루트를 사용하여 여백을 사용하여 3 개의 버튼이 어떻게 균등하게 배치되는지 보여줍니다. 다른 요소를 사용할 수 있습니다. 내부 x : Type을 단추에서 요소로 변경하십시오.
아이디어는 간단합니다. 외부 그리드를 사용하여 내부 그리드 양의 절반만큼 (음수 여백을 사용하여) 경계에서 요소의 여백을 끌어 내고 내부 그리드를 사용하여 원하는 양으로 요소를 균등하게 배치하십시오.
업데이트 : 사용자의 의견에 따르면 작동하지 않는다고 말했습니다. https://youtu.be/rPx2OdtSOYI
<StackPanel>
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Grid}">
<Setter Property="Margin" Value="-5 0"/>
</Style>
</Grid.Resources>
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Margin" Value="10 0"/>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="Btn 1" />
<Button Grid.Column="1" Content="Btn 2" />
<Button Grid.Column="2" Content="Btn 3" />
</Grid>
</Grid>
<TextBlock FontWeight="Bold" Margin="0 10">
Test
</TextBlock>
</StackPanel>
때로는 간단한 방법이 가장 좋습니다. 문자열을 공백으로 채우십시오. 단지 몇 개의 텍스트 상자 등이라면 이것이 가장 간단한 방법입니다.
고정 된 크기의 빈 열 / 행을 간단히 삽입 할 수도 있습니다. 매우 간단하며 쉽게 변경할 수 있습니다.