Как создать форму в WPF с помощью сетки или других элементов управления для удобства обслуживания

У меня есть форма WPF, я хочу выложить на него стандартную форму. Каждый элемент формы будет иметь метку, а затем элемент управления. Довольно стандартный материал.

Если я использую панель обертки, это может привести к разделению метки и элемента управления, но я хочу, чтобы они оставались вместе. Есть ли какой-либо WPF-эквивалент <nobr/>?

Сетка работает, а также позволяет перекрывать столбцы и т.д., однако я действительно очень ненавижу, что вы указываете столбец и строку для каждого элемента управления. Это делает крайне неудобным переупорядочивать или вставлять вещи в список.

Есть ли способ получить сетку для использования большего количества столбцов/строк HTML-стиля, где элементы являются дочерними элементами строки, в которой они находятся, чтобы я мог легко переупорядочить?

Есть ли какой-нибудь другой элемент управления, который позволит мне легко разместить форму?

Ответы

Ответ 1

есть ли какой-либо WPF-эквивалент nobr?

Помните, что вы можете вставлять панели:

<WrapPanel Orientation="Horizontal">
   <StackPanel Orientation="Horizontal">
      <Label>Some field</Label>
      <TextBox>Some value</TextBox>
   </StackPanel>
   <StackPanel Orientation="Horizontal">
      <Label>Another field</Label>
      <TextBox>Another value</TextBox>
   </StackPanel>
   ...
</WrapPanel>

Кроме того, для столбчатых макетов общая область сетки Grid может координировать любое количество сеток, которые ее используют:

<StackPanel Orientation="Vertical" Grid.IsSharedSizeScope="True">
   <Grid>
      <Grid.ColumnDefinitions>
         <ColumnDefinition Width="Auto" SharedSizeGroup="Label"/>
         <ColumnDefinition Width="*"/>
      </Grid.ColumnDefinitions>
      <Label Grid.Column="0">Some field</Label>
      <TextBox Grid.Column="1">Some value</TextBox>
   </Grid>
   <Grid>
      <Grid.ColumnDefinitions>
         <ColumnDefinition Width="Auto" SharedSizeGroup="Label"/>
         <ColumnDefinition Width="*"/>
      </Grid.ColumnDefinitions>
      <Label Grid.Column="0">Another field</Label>
      <TextBox Grid.Column="1">Another value</TextBox>
   </Grid>
</StackPanel>

Я ненавижу как многословный XAML для этого, тем более что вам нужно повторить определения столбцов. Хотя, если вы правильно структурируете свои классы и используете шаблоны, это не так страшно. И обратите внимание, что вы не отслеживаете номера строк в этой схеме, поэтому поля переупорядочения просты.

Ответ 2

Попробуйте использовать элемент управления UniformGrid.

Ответ 3

То, что вы, возможно, ищете, представляет собой панель стека. Использование вертикальной StackPanel позволит вам упорядочить ярлык и элементы управления. Для каждой метки и элемента управления вам может понадобиться горизонтальная панель стека, например

<StackPanel Orientation="Vertical">
  <StackPanel Orientation="Horizontal">
     <Label Width="150">Name</Label>
     <Textbox Width="200/>
  </StackPanel>
  <StackPanel Orientation="Horizontal">
     <Label Width="150">Date of Birth</Label>
     <DatePicker Width="200/>
  </StackPanel>
</StackPanel>

Теперь вы можете добавлять, удалять, редактировать и изменять порядок в своем сердечном содержимом, не беспокоясь о столбцах и строках.

Ответ 4

Ознакомьтесь с материалом Карла.

http://web.archive.org/web/20150620104259/https://karlshifflett.wordpress.com/2008/10/23/wpf-silverlight-lob-form-layout-searching-for-a-better-solution/

Простой и чистый xaml:

<pt:Form x:Name="formMain" Style="{DynamicResource standardForm}" Grid.Row="1">
  <TextBox pt:FormItem.LabelContent="_First Name" />
  <TextBox pt:FormItem.LabelContent="_Last Name"  />
  <TextBox pt:FormItem.LabelContent="_Phone" Width="150" HorizontalAlignment="Left" />
  <CheckBox pt:FormItem.LabelContent="Is _Active" />    
</pt:Form>

Ответ 5

Вот библиотека для него

Пример xaml:

<UserControl ...
             xmlns:autoRowGrid="http://gu.se/AutoRowGrid"
             ...>
    <autoRowGrid:Grid ColumnDefinitions="Auto *">
        <autoRowGrid:Row Name="first row">
            <TextBlock Text="foo1" />
            <TextBox Text="{Binding Value1}" />
        </autoRowGrid:Row>

        <autoRowGrid:Row Name="second row">
            <TextBlock Text="foo2" />
            <TextBox Text="{Binding Value2}" />
        </autoRowGrid:Row>
    </autoRowGrid:Grid>
    ...

Это расширение разметки, которое возвращает ванильный WPF Grid для красивого неглубокого визуального дерева.

NuGet

Ответ 6

Если вы согласитесь, я рекомендую Expression Blend, если вы собираетесь делать много дизайна пользовательского интерфейса. Это позволяет упростить просмотр элементов. Управление вложением в различные контейнеры - хороший способ заставить динамический интерфейс, но структурирован.

Обычно я использую панель Grid, чтобы разбить окно на функциональные области. Затем я буду использовать серию StackPanels (часто вертикальную стеклянную панель с горизонтальными StackPanels внутри нее, каждая с меткой и текстовым полем).

К сожалению, сетки работают только так, как вы заявили. Элементы в них указывают строку и/или столбец, в котором они находятся. Если вы использовали Blend, добавление Grid Columns или Rows будет иметь элементы управления, автоматически изменяющие спецификацию строки/столбца, чтобы оставаться в позиции, в которой они были размещены.

Надеюсь, что это поможет.

Expression Blend Trial в Microsoft.

UPDATE:

VS2012 имеет множество функций Expression Blend, запеченных в дизайнере WPF. Большая часть потребности в копии Blend больше не существует, поскольку разработчики имеют доступ к большому количеству интересных инструментов из Blend.

Ответ 7

В нашем продукте мы используем HeaderedContentControl для размещения форм в сетке. Шаблон управления имеет метку и отступы/поля, так что содержание управления всегда равномерно распределено. В XAML мы просто добавляем их в столбцы.

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

<Style x:Key="hccFormStyle" Targettype="{x:Type HeaderedContentControl}>
... some setters for colors, margin, padding, etc...
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
  <Label Content={Binding Content} Target={Binding Tag}> <-- pass the control for the access key with the tag
  <ContentPresenter>
</ControlTemplate>
...triggers if necessary - hover states, etc...
</style>

Затем в сетке вы определяете свои строки и столбцы и помещаете одну из них в каждую ячейку или просто вниз по каждой строке:

<HeaderedContentControl x:Name="username" Grid.Column=0 Content="User Name" Tag=textboxUserName>
 <Textbox x:Name=textboxUserName>
</HeaderedContentControl>

Я мог бы ответить на другой вопрос, но именно так мы выкладываем наши формы.

Ответ 8

У меня была та же проблема, переупорядочение элементов управления в макете на основе сетки - настоящая боль.

Итак, я написал настраиваемую панель, которая делает "форму макета" (группы из двух столбцов, все метки одинакового размера, все управляют одинаковым размером, все выровнено и т.д.), это в моем блоге: http://www.nbdtech.com/Blog/archive/2010/07/27/easy-form-layout-in-wpf-part-1-ndash-introducing-formpanel.aspx

Ответ 9

Сегодня я столкнулся с этим сообщением, имея тот же вопрос, используя ответы в этом потоке. Я придумал удобное решение для простых пар текста/текста. Чтобы добавить новые поля, просто раскройте коллекцию "FormItems".

Xmlns: C = "CLR-пространств имен: System.Collections; сборка = mscorlib"

<Window.Resources>
    <c:ArrayList x:Key="FormItems">
        <c:DictionaryEntry Key="First        Name" Value="John"/>
        <c:DictionaryEntry Key="Last Name" Value="Smith"/>
    </c:ArrayList>
</Window.Resources>

<ItemsControl ItemsSource="{StaticResource FormItems}" Grid.IsSharedSizeScope="True">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" SharedSizeGroup="Label"/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <TextBlock>
                    <Run Text="{Binding Key}"/><Run Text=": "/>
                </TextBlock>
                <TextBox Grid.Column="1" Text="{Binding Value}"/>
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Базовый результат компоновки формы

Не было учета полей и отступов, он просто показывает концепцию использования DataTemplate для повторного использования макета каждого элемента. Он может быть легко адаптирован для включения других типов данных и элементов управления. Вы даже можете использовать ItemTemplateSelector для выбора другого шаблона в зависимости от типа словаряEntry.Value

ИЗМЕНИТЬ

Другой подход, который я нашел, облегчил DataBinding, заключался в том, чтобы использовать Visual Studio для создания нового WPF "Custom Control". Это создаст новый файл с именем Themes/Generic.xaml с новым стандартом по умолчанию, определенным там. Несколько простых изменений, и мы можем использовать ItemsControl для отображения нашего нового элемента управления.

Новый класс:

public class FormControlItem : ContentControl
{
    public object Field {
        get { return base.GetValue(FieldProperty); }
        set { base.SetValue(FieldProperty, value); }
    }

    static FormControlItem() {
        DefaultStyleKeyProperty.OverrideMetadata(
            typeof(FormControlItem), 
            new FrameworkPropertyMetadata(typeof(FormControlItem)));
    }

    public static readonly DependencyProperty FieldProperty =
        DependencyProperty.Register(
            "Field",
            typeof(object),
            typeof(FormControlItem),
            new FrameworkPropertyMetadata());
}

Темы /Generic.xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:MyApplication">


    <Style TargetType="{x:Type local:FormControlItem}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:FormControlItem}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" SharedSizeGroup="Label"/>
                                <ColumnDefinition/>
                            </Grid.ColumnDefinitions>
                            <ContentPresenter ContentSource="Field"/>
                            <ContentPresenter Grid.Column="1" ContentSource="Content"/>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

</ResourceDictionary>

Пример использования:

<ItemsControl Grid.IsSharedSizeScope="True">
    <local:FormControlItem Field="Name: ">
        <TextBox Text="{Binding Path=Name}"/>
    </local:FormControlItem>
    <local:FormControlItem Field="Type: ">
        <ComboBox 
            SelectedItem="{Binding Path=Type}"
            ItemsSource="{Binding Path=TypeValues}"/>
    </local:FormControlItem>
    <local:FormControlItem Field="Category: ">
        <TextBox Text="{Binding Path=Category}"/>
    </local:FormControlItem>
</ItemsControl>

Результат компоновки пользовательского контроля