Or, to be more clear, how can I format a block of text (in my case, to be included within a tooltip) such that some portions of the text come from bound values.
In plain C# I would use:
_toolTip.Text = string.Format("{1:#0}% up, {2:#0}% down",
Environment.NewLine, percentageOne, percentage2);
However the WPF XAML markup for a Text property seems able to contain only a single binding. The curly braces gave me high hopes, but this isn't possible:
<Element>
<Element.Tooltip>
<!-- This won't compile -->
<TextBlock Text="{Binding Path=PercentageOne}% up, {Binding Path=PercentageTwo}% down"/>
</Element.Tooltip>
</Element>
I read that the Run.Text
property is not a dependency property and can therefore not be bound.
Is there a way I can perform this formatting in XAML?
-
As far as I know, WPF doesn't do what you want. You do have a much more powerful (albeit more involved) solution.
Take a look at the IValueConverter interface.
MSDN HowTo link here
EDIT
Based on aku's answer, and your assertion that you can't use 3.5 SP1, here's an alternative.
Take a look at Phil Haack's recent series of posts on string formatting:
Create a ValueConverter as that takes the format as a property. You should then be able to bind your data object and have it format based on your defined format (using property name instead of position).
Drew Noakes : Hi Michael. Thanks, but I was hoping to do something more declarative in the XAML rather than having to write a .NET type specifically catering to my requirement. It wouldn't be reusable outside of this context in the way that String.Format is reusable. -
You can use MultiBinding + StringFormat (requires WPF 3.5 SP1):
<TextBox.Text> <MultiBinding StringFormat="{}{1:#0}% up, {2:#0}% down"> <Binding Path="PercentageOne" /> <Binding Path="PercentageTwo"/> </MultiBinding> </TextBox.Text>
Regarding Run.Text - you can't bind to it but there are some workarounds:
- http://fortes.com/2007/03/20/bindablerun/
- http://paulstovell.net/blog/index.php/attached-bindablerun/
Michael Meadows : awesome, didn't know about that new feature. Do you know what the empty squiglies at the beginning of the string represents?aku : {} is necessary to tell WPF to not treat {something} as a markup extension.Drew Noakes : Cheers aku. Unfortunately I'm not targeting SP1 so will have to kludge this one. Still, I think this is the most elegant answer so I've given it to you.John Fisher : Thanks for including the link to BindableRun! -
The way I've solved this in the past is actually to break the TextBlock you have in your listing up into several TextBlocks. Try something like this:
<Element> <Element.Tooltip> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Path=PercentageOne}"/> <TextBlock Text="% up, "/> <TextBlock Text="{Binding Path=PercentageTwo}"/> <TextBlock Text="% down"/> </StackPanel> </Element.Tooltip> </Element>
Alternately you can create something like a StringFormatConverter, which could take the format string as a parameter, and use a MultiBinding to pass it the parameters. See this link for MultiBindings:
And this one for info on converters:
You can pretty easily imagine a converter that takes "object[] values" instead of "object value" as it's first parameter, and passes those on to the Format function.
aku : increasing number of visuals can harm performance, also this markup can work different when text overflow occursDrew Noakes : Thanks for the answer. I'd considered the StackPanel approach but it seems a little clunky and I was hoping for something better. Also, as aku says, it wouldn't wrap neatly. Unfortunately I'm not using SP1 so can't using MultiBinding.jomtois : A WrapPanel would solve the wrapping issue in lieu of a StackPanel -
If you're using 3.5 SP1, Aku's answer is the way to go. If you're not, you can use the FormatConverter from my WPF Converters library.
HTH, Kent
Drew Noakes : Thanks Kent, these look useful and I'll check them out today. BTW the formatting on the codeplex page you've listed doesn't look quite right towards the end of code samples (in Chrome on WinXP at least). -
I would split into multiple textblocks, binding each one with the StringFormat={0:P} in the binding as such:
<TextBox Text="{Binding Something, StringFormat=\{0:P\}}" />
See this post for examples:Lester's WPF Blog on StringFormat
Checkout VS2010 - The binding from properties includes formatting in the options.
0 comments:
Post a Comment