2009-08-24 15 views
104

Czy łatwo jest określić margines i/lub dopełnienie dla wierszy lub kolumn w siatce WPF?WPF: Siatka z marginesem kolumny/wiersza/padding?

Mógłbym oczywiście dodać dodatkowe kolumny do kosmicznych rzeczy, ale wydaje się to zadanie dla dopełnienia/marż (to daje dużo prostsza XAML). Czy ktoś może pochodzić ze standardowej siatki, aby dodać tę funkcjonalność?

+2

Jedną z użytecznych przykładów można znaleźć tutaj: http://www.codeproject.com/Articles/107468/ WPF-Padded-Grid – peter70

Odpowiedz

14

Można napisać własną GridWithMargin klasę, odziedziczoną Grid, i zastąpić metodę ArrangeOverride stosowania marginesie

67

RowDefinition i ColumnDefinition są typu ContentElement i Margin jest ściśle nieruchomość FrameworkElement. Tak więc na twoje pytanie, "jest to z łatwością możliwe" odpowiedź brzmi zdecydowanie nie. I nie, nie widziałem żadnych paneli układu, które demonstrują tego rodzaju funkcjonalność.

Możesz dodać dodatkowe wiersze lub kolumny zgodnie z sugestią. Ale możesz także ustawić marginesy na samym elemencie Grid lub cokolwiek, co znajdzie się wewnątrz Grid, więc jest to najlepsze rozwiązanie na teraz.

1

Jedną z możliwości byłoby dodać stałe wierszy i szerokość kolumn, aby pełnić rolę dopełnienia/margines szukasz dla.

Możesz również wziąć pod uwagę, że jesteś ograniczony przez rozmiar swojego kontenera i że siatka stanie się tak duża, jak element zawierający lub jego określona szerokość i wysokość. Możesz po prostu użyć kolumn i wierszy bez ustawionej szerokości ani wysokości. W ten sposób domyślnie dzielą równomiernie całkowitą przestrzeń wewnątrz siatki. Wtedy byłaby to tylko kwestia wyśrodkowania twoich elementów w pionie i poziomie w obrębie twojej siatki.

Inną metodą może być owinięcie wszystkich elementów siatki w stałą siatkę słupów o pojedynczej linii &, która ma ustalony rozmiar i margines. To, że twoja siatka zawiera stałe pola szerokości/wysokości, które zawierają twoje rzeczywiste elementy.

+0

Dzięki Adam, jednak dodanie dodatkowych kolumn/wierszy jest dokładnie tym, czego próbowałem uniknąć. Po prostu chcę zmniejszyć mój znacznik i być w stanie określić margines lub dopełnienie pomoże w tym. –

+0

Należy tylko zdefiniować dodatkowe kolumny i wiersze, a nie dodawać do nich znaku. Na przykład, jeśli chcesz dodać szerokość N między kolumnami dla 3 kolumn, będziesz miał 5 definicji kolumn. Pierwsza to szerokość automatyczna, następna ustalona, ​​a następnie automatyczna, następnie ustalona, ​​a następnie automatyczna. Następnie przypisz kolumny 1, 3 i 5 tylko do rzeczywistych elementów treści. Rozumiem twój punkt widzenia na dodatkowy znacznik kolumny, ale jeśli nie masz setek elementów, wydaje mi się to banalne. ale twoja rozmowa. Czy próbowałeś też użyć panelu stosu paneli stosu z ustawionym marginesem? –

+0

W moim przypadku dodanie kolumny "splitter/margin" było zdecydowanie najczystsze i najłatwiejsze. Dzięki! – jchristof

19

Można użyć coś takiego:

<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> 

Albo jeśli nie potrzebujemy 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> 
+22

Dzięki JayGee, jednak to rozwiązanie jest przeznaczone dla DataGrid - a nie standardowego kontrolera Grid. –

3

Zrobiłem to teraz jeden z moich siatek.

  • Najpierw zastosuj ten sam margines do każdego elementu w siatce. Możesz zrobić tę mannualię, używając stylów lub cokolwiek chcesz. Powiedzmy, że chcesz poziomy odstęp 6px i pionowy odstęp 2px. Następnie dodajesz marginesy "3px 1px" do każdego dziecka w siatce.
  • Następnie usuń marginesy utworzone wokół siatki (jeśli chcesz wyrównać granice kontrolek wewnątrz siatki do tej samej pozycji siatki). Zrób to ustawiając margines "-3px-1px" na siatkę. W ten sposób inne elementy sterowania poza siecią zostaną dostosowane do najbardziej oddalonych elementów sterujących wewnątrz sieci.
+0

Stosowanie tego samego marginesu do każdego elementu w siatce wydaje się być najprostszym sposobem. – Envil

16

Użyj kontrolę Border poza kontrolą komórek i określić padding na to:

<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> 


Źródło:

+1

Połączona strona ma teraz błąd serwera. –

+1

@RichardEverett Sprawdź maszynę Way Back: link zaktualizowano w odpowiedzi. – CJBS

3

Wpadłem na ten problem, tworząc ostatnio jakieś oprogramowanie i zdarzyło mi się zapytać DLACZEGO? Dlaczego to zrobili ... odpowiedź była tuż przede mną. Rząd danych jest obiektem, więc jeśli utrzymujemy orientację obiektową, projekt dla danego wiersza powinien być oddzielony (załóżmy, że trzeba będzie ponownie użyć wyświetlania wiersza później w przyszłości). Więc zacząłem używać paneli stosu databound i niestandardowych kontrolek dla większości wyświetlaczy danych. Listy pojawiały się sporadycznie, ale głównie sieć była używana tylko do podstawowej organizacji strony (nagłówek, obszar menu, obszar zawartości, inne obszary). Twoje niestandardowe obiekty mogą łatwo zarządzać wymaganiami dotyczącymi odstępów dla każdego wiersza w panelu stosu lub siatce (pojedyncza komórka siatki może zawierać cały obiekt wiersza, co ma dodatkową zaletę, że reaguje prawidłowo na zmiany orientacji, rozwinięcia/zwijania itp.

<Grid> 
    <Grid.RowDefinitions> 
    <RowDefinition /> 
    <RowDefinition /> 
    </Grid.RowDefinitions> 

    <custom:MyRowObject Style="YourStyleHereOrGeneralSetter" Grid.Row="0" /> 
    <custom:MyRowObject Style="YourStyleHere" Grid.Row="1" /> 
</Grid> 

lub

<StackPanel> 
    <custom:MyRowObject Style="YourStyleHere" Grid.Row="0" /> 
    <custom:MyRowObject Style="YourStyleHere" Grid.Row="1" /> 
</StackPanel> 

Twoje Własne kontrole będą również dziedziczą DataContext jeśli używasz powiązania danych ... mój ulubiony osobistych korzyści z takiego podejścia.

+0

To, co próbowaliście tutaj zrobić, to stworzyć prostą wersję kontrolki 'ListView' WPF w trybie' GridView', ale bez przepisu, aby wszystkie "RowObjects" miały tę samą szerokość kolumny. W rzeczywistości nie ma już wiele wspólnego z siatką. –

0

Choć nie można dodać margines lub padding do siatki, ty cou ld użyj czegoś podobnego do Frame (lub podobnego kontenera), do którego możesz go zastosować.

W ten sposób (jeśli pokazujesz lub ukrywasz kontrolkę po kliknięciu przycisku), nie musisz dodawać marginesu do każdego kontrolera, który może z nim współdziałać.

Pomyśl o tym, jak izolować grupy kontroli na jednostki, a następnie stosować styl do tych jednostek.

2

Myślałem, że dodam własne rozwiązanie, ponieważ nikt jeszcze o tym nie wspomniał. Zamiast projektowania UserControl opartego na Grid, możesz kierować kontrolki zawarte w siatce z deklaracją stylu. Dba o dodanie dopełnienie/margines do wszystkich elementów bez konieczności definiowania dla każdego, co jest uciążliwe i robocizna-intensive.For przykład, jeśli Siatka zawiera nic poza TextBlocks, można to zrobić:

<Style TargetType="{x:Type TextBlock}"> 
    <Setter Property="Margin" Value="10"/> 
</Style> 

Który jak odpowiednik "dopełnienia komórki".

+0

czy to spływa? na przykład jeśli masz stackpanel w rzędzie siatki, czy dzieci bloku Textboard z pakietu stackpanel dziedziczą tę właściwość? – Maslow

+0

Nie jestem pewien, czy przepływa obok najbliższych dzieci, ale można się tego dowiedzieć za pomocą prostego testu. –

+0

@Maslow Odpowiedź brzmi "tak", ale twoje sformułowanie jest trochę mylące. Nie ma "dziedziczenia" właściwości 'Margin', to znaczy, że każdy' Styl' w 'ResourceDictionary' będzie miał zastosowanie do każdego elementu jego' TargetType' wszędzie *** w całym zakresie *** właściciela tego słownika element. Więc to jest "styl", który płynie, a nie własność. –

-1

Czasami prosta metoda jest najlepsza. Po prostu stwórz struny spacjami. Jeśli jest to tylko kilka pól tekstowych itp., Jest to zdecydowanie najprostsza metoda.

Można również wstawiać puste kolumny/wiersze o ustalonym rozmiarze. Niezwykle prosty i możesz go łatwo zmienić.

+0

Dlaczego zostało to odrzucone? – rolls

2

Jak wcześniej wspomniano, utwórz klasę GridWithMargins. Oto mój przykładowy kod roboczego

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> 
+0

Zgłasza wyjątek System.ArgumentException: "Szerokość musi być nieujemna." actual.Width - = Math.Min (actual.Width, RowMargin.Left + RowMargin.Right); actual.Height - = Math.Min (actual.Height, RowMargin.Top + RowMargin.Bottom); –

0

w UWP (wersja Windows10FallCreatorsUpdate i powyżej)

<Grid RowSpacing="3" ColumnSpacing="3"> 
Powiązane problemy