views:

230

answers:

4

I'm looking for something along these lines:

<TextBlock
    Grid.Column="1"
    Text="Welcome, {Binding UserName}!" />

This will of course actually display the text "{Binding UserName}" to the user rather than decode it, but I know you can do something like this with ASP.NET, so I'm hoping there's a way to get this to work in WPF.

I'm already aware that I could use an IValueConverter...I'm looking for something I can do purely in markup if possible.

EDIT:

Based on @Matt Hamilton's most excellent solution, I attempted to push the envelope and bind two values into the same TextBlock using a MultiBinding. Works like a charm:

<TextBlock
    Style="{StaticResource TextBlock_ValueStyle}"
    Grid.Column="1">
    <TextBlock.Text>
        <MultiBinding
            StringFormat="{}Attempts: {0:G} of {1:G}">
            <Binding
                Path="AttemptNumber" />
            <Binding
                Path="AttemptCount" />
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

This produces: Attempts: 1 of 4 (assuming AttemptNumber = 1 and AttemptCount = 4).

I also found this link helpful for figuring out which formats to place after the colon:

http://msdn.microsoft.com/en-us/library/fbxft59x.aspx

A: 

So far I don't know of a solution which makes this possible in exactly the same way as you describe it. However, you can, as a workaround, use multiple text blocks to piece together your sentence:

<StackPanel Orientation="Horizontal">
    <TextBlock Text="Welcome, "/>
    <TextBlock Text="{Binding UserName}"/>
    <TextBlock Text="!"/>
</StackPanel>

This is what I used so far and while cumbersome to type it seems to be the easiest solution. But as soon as you need Internationalization it's a no-go for obvious reasons.

Joey
I've used a `StackPanel` to string together attribute-value pairs before (e.g., "Status: Successful"), but I was a little wary to use it to string together different parts of a sentence because I thought the natural text spacing might not be preserved (i.e., you'd have larger breaks between `TextBlocks` than between words of the same `TextBlock`. If this turns out to not be a problem, though, this is a good solution.
DanM
So far I noticed no extra space. But kerning most likely won't work as will automatic ligatures, etc. Essentially you break the text into different runs and I doubt advanced typography works across those. But for some projects the i18n part is a pretty serious one and I avoid concatenating strings and variables or using non-positional format strings wherever possible. Sometimes a quick and dirty solution like this survives, though :-)
Joey
+8  A: 

You can use the StringFormat binding property in .NET 3.5 SP1:

<TextBlock Text="{Binding UserName,StringFormat='Welcome, \{0\}!'}" />

Note that you need to escape the curly braces in the string format with a backslash.

Update Yes, multiple values are also supported:

<TextBlock>
    <TextBlock.Text>
        <MultiBinding StringFormat="Welcome, {0} {1}!">
            <Binding Path="FirstName" />
            <Binding Path="LastName" />
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>
Matt Hamilton
Whee, that's nice. The ordering is weird, though, as it's exactly the opposite with the usual [string]::Format.
Joey
Beautiful! This leads me to another question, though: Is it possible to have multiple bound values or are you limited to one? Thanks.
DanM
Answered my own question (see my edit).
DanM
D'oh - you did that while I was updating my answer! Oh well! :)
Matt Hamilton
@Johannes you can order it the same was as String.Format if you like: Text="{Binding StringFormat='...',Path=UserName"
Matt Hamilton
@Matt: Haha, well I guess it doesn't hurt to have two examples. There are weird rules with escaping of the braces I haven't quite gotten a handle on yet. Notice in my example, I used `{}` at the beginning of the `StringFormat`. In your original example you used `\{` and `\}`. And then you didn't need to escape at all for your second example. Also, it rejected my integer bindings until I added `:G` ("general" format). Those weirdnesses aside, `StringFormat` has a new fan.
DanM
Ah, right. It's been a while since I've been in WPF-land.
Joey
A: 

Have a look at this library "WPFix". It allows the user to write lambda expressions in the XAML. I didn't use it in production code, only in demo code. I was able to take the width of a form, divide it by two, and bind the value to a control. Ordinarily, you would need to create a converter class, as you describe. This library may be the thing you are looking for:

http://www.fikrimvar.net/lestirelim/?p=15

MedicineMan
A: 

This is simplest way to mix text and controls

<TextBlock>Welcome, <TextBlock Text="{Binding UserName}"/>!</TextBlock>

you can inline styled buttons or other controls to.

gimalay