views:

453

answers:

4

Hi, I am wondering, which is the best and quickest way to get the well known Label Input [or output, doesn't matter] combination in WPF. Its a simple Task, just think of a quick output of the "object" ME:


Name - Christian

Age - 28

Mood - Good


I know, I can use a Grid with TextBlocks. But to be honest, the "short" XAML for this is nearly half a page long (RowDefinitions, ColDefs, Grid.Col on each Label)

The alternative way, using three StackPanels (horizontal) with one vertical seems also a little bit stupid. In this case, I have to give each Label a fixed width, to get the indent correct. And it just does not "feel" right.

So, given the Situation above, you got a custom object with 3-6 Properties you just want to dump as readonly to your GUI, how would you do it (in WPF, Silverlight too, if you are really in the mood :).

I can, of course, write a usercontrol for this. But why reinvent the wheel, if it might be already there...

And finally, to illustrate even further, the example I just created in real life and was the reason for this post:

      <StackPanel>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Log Count"  Width="100"/>
            <TextBlock Text="{Binding LastLogRun.LogMessageCount}"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Start Time" Width="100"/>
            <TextBlock Text="{Binding LastLogRun.StartTime}"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="End Time" Width="100"/>
            <TextBlock Text="{Binding LastLogRun.EndTime}"/>
        </StackPanel>
    </StackPanel>
A: 

Perhaps you should rethink your UI. Why would you want Label - Textbox on the same line? That's a horrendous waste of space.

Why not Label over texbox? Then you've got a simple UI and simple XAML:

<StackPanel Orientation="Vertical">
  <TextBlock>Name</TextBlock>
  <TextBox />
  <TextBlock>Age</TextBlock>
  <TextBox />
  <TextBlock>Mood</TextBlock>
  <TextBox />
</StackPanel>

Add some styling for your TextBlocks and you've got a nice, clean UI, with very little repetition.

Randolpho
Why are you accusing OP of wasting screen space, when your approach wastes far more? Think about it: with OP's approach, a "Name" label takes up 42x26 = 1092 pixels. With your approach, that same label is the full width of the screen, so on my monitor, even if I give you a head start by setting Padding=0, yours takes 1440x16 = 23040 pixels. Your layout is a legitimate option, but don't kid yourself that it's less wasteful of real estate.
Joe White
Randolpho's solution is good, not because it uses less screen space, but because it is easier to internationalize. By putting the Label above the TextBox, the spacing does change and the length of the labels change for different languages.
John Myczek
+1  A: 

If you're using 3.5sp1 you can use StringFormat in the binding. Something like this should work...

<TextBlock Text="{Binding LastLogRun.LogMessageCount, StringFormat={}Log Count - {0}}" />
Bryan Anderson
+1  A: 

You could use shared size groups to get the auto-sizing Grid behavior of two nicely-lined-up columns, while still being able to pull out the complexity into a UserControl.

Here's an example of using a LabeledEdit control that would do what you're looking for. The complexity has all been factored away into the UserControl, and all you need to do is remember to set Grid.IsSharedSizeScope on the StackPanel:

<Window x:Class="WpfApplication5.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication5"
        Name="Self" Title="Window1" Height="300" Width="300">
    <StackPanel Grid.IsSharedSizeScope="True">
        <local:LabeledEdit Label="Name"/>
        <local:LabeledEdit Label="Age" Text="28"/>
        <!-- and with databinding... -->
        <local:LabeledEdit Label="Width"
                           Text="{Binding Width, ElementName=Self}"/>
        <local:LabeledEdit Label="Height"
                           Text="{Binding Height, ElementName=Self}"/>
    </StackPanel>
</Window>

And here's the source code for the UserControl. LabeledEdit.xaml:

<UserControl x:Class="WpfApplication5.LabeledEdit"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             Name="Self">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" SharedSizeGroup="LabeledEdit_Labels"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Label Grid.Column="0" Content="{Binding Label, ElementName=Self}"/>
        <TextBox Grid.Column="1" Text="{Binding Text, ElementName=Self}"/>
    </Grid>
</UserControl>

LabeledEdit.xaml.cs:

using System.Windows;

namespace WpfApplication5
{
    public partial class LabeledEdit
    {
        public static readonly DependencyProperty LabelProperty =
            DependencyProperty.Register("Label", typeof(object), typeof(LabeledEdit));
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(string), typeof(LabeledEdit),
            new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

        public LabeledEdit()
        {
            InitializeComponent();
        }

        public object Label
        {
            get { return GetValue(LabelProperty); }
            set { SetValue(LabelProperty, value); }
        }
        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }
    }
}
Joe White
A: 

The silverlight toolkit has a DataForm control that works pretty cool!

rudigrobler