开发者

How do I layout a form in WPF using grid or other controls for maintainability [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.

Want to improve this question? Update the question so it focuses on one problem only by editing this post.

Closed 2 years ago.

Improve this question

I have a WPF form, I want to lay out a sta开发者_如何学Pythonndard form onto it. Each form element will have a label, and then a control. Pretty standard stuff.

If I use a wrap panel, it can cause the label and the control to be separated, but I want them to stay together. Is there some WPF equivalent of <nobr/>?

Grid works, and allows for column spanning etc, however I really really hate that you specify the column and row on each control. This makes it extremely inconvenient to reorder or insert things into the list.

Is there a way to get the grid to use more HTML style column/rows where the items are a child of the row they are in, so that I can re-order easily?

Is there some other control that will let me layout a form easily?


is there some WPF equivalent of nobr?

Remember that you can nest panels:

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

Also, for columnar layouts, the shared size scope of the Grid can coordinate any number of grids that use it:

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

I kind of hate how verbose the XAML for this is, especially that you have to repeat the column definitions. Though if you structure your classes properly and use templates it's not so terrible. And notice that you aren't keep track of row numbers anywhere in this scheme, so reordering fields is simple.


What you might be looking for is a stack panel. Using a vertical StackPanel will allow you to arrange your label and controls consistently. For each label and control you might want a horizontal stack panel like so

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

Now you can add, remove, edit, and reorder to your heart's content without worrying about columns and rows.


Try the UniformGrid control.


If you can accord it, I recommend Expression Blend if you are going to be doing much UI design. It allows a simpler view of the items. Nesting controls into various containers is a good way to get the UI to be dynamic, but structured.

Typically I will use a Grid panel to break a window up into functional areas. Then I will use a series of StackPanels (often a vertical stack panel with horizontal StackPanels inside it, each with a label and textbox).

Unfortunately Grids only work as you stated. Elements in them specify the row and/or column that they reside in. If you used Blend, adding Grid Columns or Rows will have controls auto-magically change the row/column specification to stay in the position they were placed.

Hope it helps.

Expression Blend Trial at Microsoft.

UPDATE:

VS2012 has a lot of the Expression Blend functionality baked into the WPF designer. Much of the need for a copy of Blend is no longer there as developers have access to a lot of the cool tools from Blend.


Here is a library for it

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

It is a markupextension that returns a vanilla WPF Grid for a nice shallow visual tree.

How do I layout a form in WPF using grid or other controls for maintainability [closed]


I came across this post today while having the same question, using the answers in this thread I came up with a manageable solution to simple text/text pairs. To add new fields simply expand the "FormItems" collection.

xmlns:c="clr-namespace:System.Collections;assembly=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>

How do I layout a form in WPF using grid or other controls for maintainability [closed]

There has been no consideration for margins and padding, it just shows the concept of using a DataTemplate to reuse the layout of each item. It can be adapted to include other data types and controls fairly easily. You could even use the ItemTemplateSelector to select a different template based on the type of the DictionaryEntry.Value

EDIT

Another approach that I found that made it easier for DataBinding was to use Visual Studio to create a new WPF "Custom Control". Doing so will create a new file named Themes/Generic.xaml with a new default layout defined there. A few simple edits and we can use the ItemsControl to display our new control.

New class:

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());
}

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

Usage example:

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

How do I layout a form in WPF using grid or other controls for maintainability [closed]


Check out Karl's stuff.

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

Simple and clean 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>


In our product we use a HeaderedContentControl to lay out forms in a grid. The control template has a label and padding/margins so that the control's content is always spaced appropriately. In the XAML we just add them down the columns.

I'd post some XAML but I'm in the middle of getting a new computer set up. :| But from what I remember it would look something like this:

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

Then in the grid, you define your rows and columns, and put one of these in each cell, or just down each row:

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

I might be answering a different question but this is how we lay out our forms.


I had the same problem, reordering controls in a Grid based layout is a real pain.

So I've wrote a custom panel that does "form layout" (groups of two columns, all labels same size, all control same size,everything aligned, etc.), it's on my blog at: http://www.nbdtech.com/Blog/archive/2010/07/27/easy-form-layout-in-wpf-part-1-ndash-introducing-formpanel.aspx

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜