Concatenate strings instead of using a stack of TextBlocks
Asked Answered
J

4

100

I want to show a list of Customer objects in a WPF ItemsControl. I've created a DataTemplate for this:

    <DataTemplate DataType="{x:Type myNameSpace:Customer}">
        <StackPanel Orientation="Horizontal" Margin="10">
            <CheckBox"></CheckBox>
            <TextBlock Text="{Binding Path=Number}"></TextBlock>
            <TextBlock Text=" - "></TextBlock>
            <TextBlock Text="{Binding Path=Name}"></TextBlock>
        </StackPanel>
    </DataTemplate>

So what I want basically is a simple list (with checkboxes) that contains NUMBER - NAME. Isn't there a way in which I can concat the number and name directly in the Binding part?

Jumble answered 12/2, 2009 at 15:48 Comment(0)
P
197

There is StringFormat property (in .NET 3.5 SP1), which you probably can use. And usefull WPF binding cheat sheat can found here. If it doesn't help, you can allways write your own ValueConverter or custom property for your object.

Just checked, you can use StringFormat with multibinding. In your case code will be something like this:

<TextBlock>
  <TextBlock.Text>
    <MultiBinding StringFormat=" {0} - {1}">
        <Binding Path="Number"/>
        <Binding Path="Name"/>
    </MultiBinding>
  </TextBlock.Text>
</TextBlock>

I had to start format string with space, otherwise Visual Studio wouldn't build, but I think you will find way get around it :)

Edit
The space is needed in the StringFormat to keep the parser from treating {0} as an actual binding. Other alternatives:

<!-- use a space before the first format -->
<MultiBinding StringFormat=" {0} - {1}">

<!-- escape the formats -->
<MultiBinding StringFormat="\{0\} - \{1\}">

<!-- use {} before the first format -->
<MultiBinding StringFormat="{}{0} - {1}">
Pistole answered 12/2, 2009 at 16:6 Comment(6)
Instead of the space you can use {}, e.g. StringFormat="{}{0} - {1}"Crotchet
You can also escape the braces with backslashes: <MultiBinding StringFormat="\{0\} - \{1\}">Naples
Also, the closing TextBlock is missing, so to summarize the comments: <TextBlock > <TextBlock.Text> <MultiBinding StringFormat="{}{0} - {1}"> <Binding Path="Number"/> <Binding Path="Name"/> </MultiBinding> </TextBlock.Text> </TextBlock>Benfield
@Pistole if i want to show 'number' even if 'name' is empty- how do i do that?Decemvir
@Decemvir unfortunately I won't be able to to help with your question as I haven't worked with WPF for several years. It's funny how fast you forget things you aren't working with anymore.Pistole
Would expanding StringFormat to its nested element work without needing to escape things or same trouble?Barbaric
I
82

In case you want to concat a dynamic value with a static text, try this:

<TextBlock Text="{Binding IndividualSSN, StringFormat= '\{0\} (SSN)'}"/>

Displays: 234-334-5566 (SSN)

Illumination answered 28/2, 2013 at 13:46 Comment(1)
ToolTip not work.Generalship
C
10

See the following example I used in my code using Run class:

        <TextBlock x:Name="..." Width="..." Height="..."
            <Run Text="Area="/>
            <Run Text="{Binding ...}"/>
            <Run Text="sq.mm"/>
            <LineBreak/>
            <Run Text="Min Diameter="/>
            <Run Text="{Binding...}"/>
            <LineBreak/>
            <Run Text="Max Diameter="/>
            <Run Text="{Binding...}"/>
        </TextBlock >
Communist answered 2/2, 2014 at 10:33 Comment(0)
C
3

You can also use a bindable run. Useful stuff, especially if one wants to add some text formatting (colors, fontweight etc.).

<TextBlock>
   <something:BindableRun BoundText="{Binding Number}"/>
   <Run Text=" - "/>
   <something:BindableRun BoundText="{Binding Name}"/>
</TextBlock>

Here's an original class:
Here are some additional improvements.
And that's all in one piece of code:

public class BindableRun : Run
    {
        public static readonly DependencyProperty BoundTextProperty = DependencyProperty.Register("BoundText", typeof(string), typeof(BindableRun), new PropertyMetadata(new PropertyChangedCallback(BindableRun.onBoundTextChanged)));

        private static void onBoundTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((Run)d).Text = (string)e.NewValue;
        }

        public String BoundText
        {
            get { return (string)GetValue(BoundTextProperty); }
            set { SetValue(BoundTextProperty, value); }
        }

        public BindableRun()
            : base()
        {
            Binding b = new Binding("DataContext");
            b.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(FrameworkElement), 1);
            this.SetBinding(DataContextProperty, b);
        }
    }
Conglomeration answered 12/2, 2009 at 16:50 Comment(2)
<Run Text="{Binding...}"/> ? Can you explain the advantages?Heterosexual
No difference; Run didn't support bindings on the Text property 10 years ago when this answer was written!Testimonial

© 2022 - 2024 — McMap. All rights reserved.