2

Хочу расположить на форме пары Label + какой-нибудь Combobox.

В принципе, если располагать все через Grid, то все весьма красиво получается:

   <Grid >
        <Grid.Resources >
            <Style TargetType="Border" >
                <Setter Property="Padding" Value="5,5,5,5" />
            </Style>
        </Grid.Resources>
        <Grid.ColumnDefinitions>
            <ColumnDefinition ></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
        </Grid.RowDefinitions>
        <Label Grid.Row="0" Grid.Column="0">Тип БД</Label>
        <ComboBox Grid.Row="0" Grid.Column="1"></ComboBox>
        <Label Grid.Row="1" Grid.Column="0">База данных</Label>
        <ComboBox Grid.Row="1" Grid.Column="1"></ComboBox>
        <Label Grid.Row="2">Таблица</Label>
        <ComboBox Grid.Row="2" Grid.Column="1"></ComboBox>
        <Label Grid.Row="3">Ключ таблицы</Label>
        <ComboBox Grid.Row="3" Grid.Column="1"></ComboBox>
        <Label Grid.Row="4">Значение таблицы</Label>
        <ComboBox Grid.Row="4" Grid.Column="1"></ComboBox>
        <Label Grid.Row="5">Идентификатор привязки к справочнику</Label>
        <ComboBox Grid.Row="5" Grid.Column="1"></ComboBox>
    </Grid>

введите сюда описание изображения Но мне не нравится то, что в разметке парные-элементы никак не группируются между собой...

Я попробовал попарно их засунуть каждый в свой StackPanel, но в итоге не все так красиво получается, как в Grid... Как я могу решить проблему, чтобы элементы занимали по 50% рабочей области окна?

demonplus
  • 878
iluxa1810
  • 24,899
  • Сразу замечание - выкинуть все Label, и использовать TextBlock. Причин много, не буду все перечислять. По поводу остальной разметки - вот пример с использованием DockPanel. – aepot Mar 16 '21 at 12:40
  • @aepot комбобоксы очень узиникими становятся=( Это нужно им минимальную ширину задать или как-то процентное соотношене можно? – iluxa1810 Mar 16 '21 at 14:56
  • Если хочется красиво, то лучше тут ItemsControl с шаблоном в виде Grid, а сам список сформировать в VM. Если так и хочешь статику оставить, то используй UniformGrid. В нем задаёшь Columns="2" и в него засовывать все эти элементы без Grid.Row и Grid.Column. UniformGrid сам распихнет все элементы по ячейка в порядке их описания в Xaml. Соответственно и Grid.Definition тоже не нужны будут. Но решение так себе, как по мне. – Иван Mar 16 '21 at 16:31

1 Answers1

0

Но мне не нравится то, что в разметке парные-элементы никак не группируются между собой...

Сгруппировать то легко, запихнуть каждую пару в свой Grid, да и все тут. Поведение в отношении размера стобцов у одного Grid и последовательности однострочных Grid идентично. Но, глядя на вашу разметку, смущает скорее дублирование строк и элементов. Если у вас в разметке куча однотипных пар Label + (что-то), которые ходят вместе и образуют строку таблицы, должны ли они быть отдельными элементами? По моему, это отличный повод для создания своего элемента управления.

Раз нам нужно поведение Grid в плане изменения размеров столбцов, этот элемент управления можно сделать производным от Grid:

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;

namespace WpfTest { public class ControlPair : Grid { UIElement first; UIElement second;

    public UIElement First
    {
        get { return this.first; }
        set
        {
            this.first = value;
            UpdateChildren();
        }
    }

    public UIElement Second
    {
        get{ return this.second; }

        set
        {
            this.second = value;
            UpdateChildren();
        }
    }

    void UpdateChildren()
    {
        this.Children.Clear();

        if (this.first != null)
        {
            this.Children.Add(this.first);
            Grid.SetColumn(this.first, 0);
        }

        if (this.second != null)
        {
            this.Children.Add(this.second);
            Grid.SetColumn(this.second, 1);
        }
    }

    public ControlPair() : base()
    {
        this.ColumnDefinitions.Clear();
        this.ColumnDefinitions.Add(new ColumnDefinition()
        {
            Width = new GridLength(0.5, GridUnitType.Star)
        });

        this.ColumnDefinitions.Add(new ColumnDefinition()
        {
            Width = new GridLength(0.5, GridUnitType.Star)
        });

        this.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
    }
}

}

Здесь у элемента управления есть два свойства, First и Second, которым можно присвоить любой элемент управления. Элементы помещаются в ячейки Grid, для которых задан определенный процент доступного пространства. Тогда мы можем в разметке делать так:

<local:ControlPair>
    <local:ControlPair.First>
        <Label Content="Тип БД"></Label>
    </local:ControlPair.First>
    <local:ControlPair.Second>
        <ComboBox/>
    </local:ControlPair.Second>
</local:ControlPair>

И элементы сгруппированы, и не нужна куча RowDefinition.

Более развернутый пример, как это можно применить на практике:

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfTest" x:Class="WpfTest.MainWindow"
        Height="250" Width="400" >
    <Grid>        
        <StackPanel>
        &lt;local:ControlPair HorizontalAlignment=&quot;Stretch&quot;&gt;
            &lt;local:ControlPair.First&gt;
                &lt;Label Content=&quot;Тип БД&quot;&gt;&lt;/Label&gt;
            &lt;/local:ControlPair.First&gt;
            &lt;local:ControlPair.Second&gt;
                &lt;ComboBox ItemsSource=&quot;{Binding Path=DatabaseTypeValues}&quot;
                    Text=&quot;{Binding Path=DatabaseTypeSelected,Mode=TwoWay}&quot;/&gt;
            &lt;/local:ControlPair.Second&gt;
        &lt;/local:ControlPair&gt;

        &lt;local:ControlPair HorizontalAlignment=&quot;Stretch&quot;&gt;
            &lt;local:ControlPair.First&gt;
                &lt;Label Content=&quot;База данных&quot;&gt;&lt;/Label&gt;
            &lt;/local:ControlPair.First&gt;
            &lt;local:ControlPair.Second&gt;
                &lt;TextBox Text=&quot;{Binding Path=Database,Mode=TwoWay}&quot;/&gt;
            &lt;/local:ControlPair.Second&gt;
        &lt;/local:ControlPair&gt;

        &lt;Button x:Name=&quot;myButton&quot; Content=&quot;Save&quot; HorizontalAlignment=&quot;Left&quot; Height=&quot;40&quot; Margin=&quot;10,10,10,10&quot; 
            VerticalAlignment=&quot;Top&quot; Width=&quot;100&quot; Click=&quot;Button_Click&quot; /&gt;

    &lt;/StackPanel&gt;
&lt;/Grid&gt;

</Window>

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;

namespace WpfTest
{
    public partial class MainWindow : Window
    {
        Options optionsData;

        public MainWindow()
        {
            InitializeComponent();
            optionsData = new Options();
            optionsData.DatabaseTypeValues = new string[] { "SQL Server", "Access" };            
            this.DataContext = optionsData;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            //show selected options
            MessageBox.Show("Selected " +
                "\nDatabaseType: " + optionsData.DatabaseTypeSelected +
                "\nDatabase: " + optionsData.Database
                );
        }
    }

    public class Options
    {
        public string[] DatabaseTypeValues { get; set; }
        public string DatabaseTypeSelected { get; set; }
        public string Database { get; set; }
    }
}

screenshot