Use StringFormat to add a string to a WPF XAML binding - c#

I have a WPF 4 application that contains a TextBlock which has a one-way binding to an integer value (in this case, a temperature in degrees Celsius). The XAML looks like this:
<TextBlock x:Name="textBlockTemperature">
<Run Text="{Binding CelsiusTemp, Mode=OneWay}"/></TextBlock>
This works fine for displaying the actual temperature value but I'd like to format this value so it includes °C instead of just the number (30°C instead of just 30). I've been reading about StringFormat and I've seen several generic examples like this:
// format the bound value as a currency
<TextBlock Text="{Binding Amount, StringFormat={}{0:C}}" />
and
// preface the bound value with a string and format it as a currency
<TextBlock Text="{Binding Amount, StringFormat=Amount: {0:C}}"/>
Unfortunately, none of the examples I've seen have appended a string to the bound value as I'm trying to do. I'm sure it's got to be something simple but I'm not having any luck finding it. Can anyone explain to me how to do that?

Your first example is effectively what you need:
<TextBlock Text="{Binding CelsiusTemp, StringFormat={}{0}°C}" />

Here's an alternative that works well for readability if you have the Binding in the middle of the string or multiple bindings:
<TextBlock>
<Run Text="Temperature is "/>
<Run Text="{Binding CelsiusTemp}"/>
<Run Text="°C"/>
</TextBlock>
<!-- displays: 0°C (32°F)-->
<TextBlock>
<Run Text="{Binding CelsiusTemp}"/>
<Run Text="°C"/>
<Run Text=" ("/>
<Run Text="{Binding Fahrenheit}"/>
<Run Text="°F)"/>
</TextBlock>

Please note that using StringFormat in Bindings only seems to work for "text" properties. Using this for Label.Content will not work

In xaml
<TextBlock Text="{Binding CelsiusTemp}" />
In ViewModel, this way setting the value also works:
public string CelsiusTemp
{
get { return string.Format("{0}°C", _CelsiusTemp); }
set
{
value = value.Replace("°C", "");
_CelsiusTemp = value;
}
}

Related

Windows Phone 8.1 XAML StringFormat

I am trying to display some text along with binded data, for example, I have the code:
<TextBlock Text="{Binding Shorthand}" Style="{ThemeResource ListViewItemTextBlockStyle}" />
I want to add some text before 'Shorthand', from what I have read this would be possible by using StringFormat as a property of the Binding, something along the lines of:
<TextBlock Text="{Binding Path=Shorthand, StringFormat={0} text I want to add}" Style="{ThemeResource ListViewItemTextBlockStyle}" />
However this doesn't seem to work, is this no longer the way to do things in 8.1?
StringFormat isn't supported on WinRT. However, you can easily replace it by creating a custom converter:
public class StringFormatConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return string.Format(parameter as string, value);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return null;
}
}
Then declare it in your page resources:
<Page.Resources>
<local:StringFormatConverter x:Name="StringFormat"/>
</Page.Resources>
And use it in your bindings:
<TextBlock Text="{Binding Path=SomeText, Converter={StaticResource ResourceKey=StringFormat}, ConverterParameter='Hello {0}'}" />
Like #KooKiz pointed out StringFormat at the moment isn't supported, but you could accomplish the same effect just breaking out your lines into inline Runs without a converter like;
<TextBlock>
<Run Text="Hey I wanted to put this text in front of "/>
<Run Text="{Binding Path=Shorthand}"/>
<Run Text=" and I also wanted some text after it. Neato.."/>
</TextBlock>
Hope this helps, cheers.
I used this approach (Written by Microsoft): https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.data.ivalueconverter
It works great!

Styling string from Viewmodel in Windows 8 metro

I am following MVVM pattern for my project and wanted to bind a string property to a TextBlock Text property.I want some of the words in the string property hace different color like
User has completed the Survey
I am not getting how to achieve this multicolored string in viewmodel.
I wanted this should happen in viewmodel because this message is dependent on conditions.
You could use the Run property
non mvvm
<Run Foreground="Blue">User</Run>
<Run Foreground="Black">has completed the</Run>
<Run Foreground="Blue">Survey</Run>
</TextBlock>
or Mvvm you could have your view model format the strings and then just bind to the relevant properties
<TextBlock>
<Run Text={Binding your_mvvm_property}" Foreground="{StaticResource your_style"/>
<Run Text={Binding your_mvvm_property2}" Foreground="{StaticResource your_style2"/>
</TextBlock>

Formatting text in a TextBlock

How do I achieve formatting of a text inside a TextBlock control in my WPF application?
e.g.: I would like to have certain words in bold, others in italic, and some in different colors, like this example:
The reason behind my question is this actual problem:
lblcolorfrom.Content = "Colour From: " + colourChange.ElementAt(3).Value.ToUpper();
I would like the second part of the string to be bold, and I know that I could use two controls (Labels, TextBlocks, etc.) but I'd rather not, due the vast amount of controls already in use.
You need to use Inlines:
<TextBlock.Inlines>
<Run FontWeight="Bold" FontSize="14" Text="This is WPF TextBlock Example. " />
<Run FontStyle="Italic" Foreground="Red" Text="This is red text. " />
</TextBlock.Inlines>
With binding:
<TextBlock.Inlines>
<Run FontWeight="Bold" FontSize="14" Text="{Binding BoldText}" />
<Run FontStyle="Italic" Foreground="Red" Text="{Binding ItalicText}" />
</TextBlock.Inlines>
You can also bind the other properties:
<TextBlock.Inlines>
<Run FontWeight="{Binding Weight}"
FontSize="{Binding Size}"
Text="{Binding LineOne}" />
<Run FontStyle="{Binding Style}"
Foreground="Binding Colour}"
Text="{Binding LineTwo}" />
</TextBlock.Inlines>
You can bind through converters if you have bold as a boolean (say).
You can do this in XAML easily enough:
<TextBlock>
Hello <Bold>my</Bold> faithful <Underline>computer</Underline>.<Italic>You rock!</Italic>
</TextBlock>
There are various Inline elements that can help you, for the simplest formatting options you can use Bold, Italic and Underline:
<TextBlock>
Sample text with <Bold>bold</Bold>, <Italic>italic</Italic> and <Underline>underlined</Underline> words.
</TextBlock>
I think it is worth noting, that those elements are in fact just shorthands for Span elements with various properties set (i.e.: for Bold, the FontWeight property is set to FontWeights.Bold).
This brings us to our next option: the aforementioned Span element.
You can achieve the same effects with this element as above, but you are granted even more possibilities; you can set (among others) the Foreground or the Background properties:
<TextBlock>
Sample text with <Span FontWeight="Bold">bold</Span>, <Span FontStyle="Italic">italic</Span> and <Span TextDecorations="Underline">underlined</Span> words. <Span Foreground="Blue">Coloring</Span> <Span Foreground="Red">is</Span> <Span Background="Cyan">also</Span> <Span Foreground="Silver">possible</Span>.
</TextBlock>
The Span element may also contain other elements like this:
<TextBlock>
<Span FontStyle="Italic">Italic <Span Background="Yellow">text</Span> with some <Span Foreground="Blue">coloring</Span>.</Span>
</TextBlock>
There is another element, which is quite similar to Span, it is called Run. The Run cannot contain other inline elements while the Span can, but you can easily bind a variable to the Run's Text property:
<TextBlock>
Username: <Run FontWeight="Bold" Text="{Binding UserName}"/>
</TextBlock>
Also, you can do the whole formatting from code-behind if you prefer:
TextBlock tb = new TextBlock();
tb.Inlines.Add("Sample text with ");
tb.Inlines.Add(new Run("bold") { FontWeight = FontWeights.Bold });
tb.Inlines.Add(", ");
tb.Inlines.Add(new Run("italic ") { FontStyle = FontStyles.Italic });
tb.Inlines.Add("and ");
tb.Inlines.Add(new Run("underlined") { TextDecorations = TextDecorations.Underline });
tb.Inlines.Add("words.");
Check out this example from Charles Petzolds Bool Application = Code + markup
//----------------------------------------------
// FormatTheText.cs (c) 2006 by Charles Petzold
//----------------------------------------------
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Documents;
namespace Petzold.FormatTheText
{
class FormatTheText : Window
{
[STAThread]
public static void Main()
{
Application app = new Application();
app.Run(new FormatTheText());
}
public FormatTheText()
{
Title = "Format the Text";
TextBlock txt = new TextBlock();
txt.FontSize = 32; // 24 points
txt.Inlines.Add("This is some ");
txt.Inlines.Add(new Italic(new Run("italic")));
txt.Inlines.Add(" text, and this is some ");
txt.Inlines.Add(new Bold(new Run("bold")));
txt.Inlines.Add(" text, and let's cap it off with some ");
txt.Inlines.Add(new Bold(new Italic (new Run("bold italic"))));
txt.Inlines.Add(" text.");
txt.TextWrapping = TextWrapping.Wrap;
Content = txt;
}
}
}
a good site, with good explanations:
http://www.wpf-tutorial.com/basic-controls/the-textblock-control-inline-formatting/
here the author gives you good examples for what you are looking for! Overal the site is great for research material plus it covers a great deal of options you have in WPF
Edit
There are different methods to format the text. for a basic formatting (the easiest in my opinion):
<TextBlock Margin="10" TextWrapping="Wrap">
TextBlock with <Bold>bold</Bold>, <Italic>italic</Italic> and <Underline>underlined</Underline> text.
</TextBlock>
Example 1 shows basic formatting with Bold Itallic and underscored text.
Following includes the SPAN method, with this you van highlight text:
<TextBlock Margin="10" TextWrapping="Wrap">
This <Span FontWeight="Bold">is</Span> a
<Span Background="Silver" Foreground="Maroon">TextBlock</Span>
with <Span TextDecorations="Underline">several</Span>
<Span FontStyle="Italic">Span</Span> elements,
<Span Foreground="Blue">
using a <Bold>variety</Bold> of <Italic>styles</Italic>
</Span>.
</TextBlock>
Example 2 shows the span function and the different possibilities with it.
For a detailed explanation check the site!
Examples
This is my solution....
<TextBlock TextWrapping="Wrap" Style="{DynamicResource InstructionStyle}">
<Run Text="This wizard will take you through the purge process in the correct order." FontWeight="Bold"></Run>
<LineBreak></LineBreak>
<Run Text="To Begin, select" FontStyle="Italic"></Run>
<Run x:Name="InstructionSection" Text="'REPLACED AT RUNTIME'" FontWeight="Bold"></Run>
<Run Text="from the menu." FontStyle="Italic"></Run>
</TextBlock>
I am learning... so if anyone has thaughts on the above solution please share! :)

Code equivalent of XAML snippet

I want to know the code equivalent of the part that is inside the TextBlock:
<TextBlock>
Hello
<Run Background="Red">S</Run>
<Run Background="Blue">O</Run>
</TextBlock>
The reason is that I have a converter that returns the TextBox content, but I'm not sure what type to return from the converter. I tried some collection types, that contain the string and the 2 Run instances but that wouldnt work.
Also I noticed that the following wouldnt work:
<TextBlock>
<TextBlock.Text> <--- Added this
Hello
<Run Background="Red">S</Run>
<Run Background="Blue">O</Run>
</TextBlock.Text>
</TextBlock>
So my second question is to which property do I have to bind my converter result?
Firstly, you can add Run blocks via the InLines property, e.g.
TextBlock txtBlock = new TextBlock();
txtBlock.Inlines.Add(new Run { Text = "S", Background = Brushes.Red });
txtBlock.Inlines.Add(new Run { Text = "O", Background = Brushes.Blue });
Secondly, you cannot add via "TextBlock.Text" as this is expecting a string, not a collection of Runs.
Try this:
<Label>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Hello"/>
<TextBlock Background="Red" Text="S"/>
<TextBlock Background="Blue" Text="O"/>
</StackPanel>
</Label>
Add your converter to the binding of each textblocks.I think its more flexible than using the Run

WPF: Cannot set properties on property elements weirdness

private TextBlock _caption = new TextBlock();
public TextBlock Caption
{
get { return _caption; }
set { _caption = value; }
}
<l:CustomPanel>
<l:CustomPanel.Caption Text="Caption text" FontSize="18" Foreground="White" />
</l:CustomPanel>
Gives me the following error:
Cannot set properties on property elements.
If I use:
<l:CustomPanel>
<l:CustomPanel.Caption>
<TextBlock Text="Caption text" FontSize="18" Foreground="White" />
</l:CustomPanel.Caption>
</l:CustomPanel>
My TextBlock shows up fine but it's nested inside another TextBlock like so, it even seems to add itself outside of the Caption property:
<l:CustomPanel>
<l:CustomPanel.Caption>
<TextBlock>
<InlineUIContainer>
<TextBlock Text="Caption text" FontSize="18" Foreground="White" />
</InlineUIContainer>
</TextBlock>
</l:CustomPanel.Caption>
<TextBlock>
<InlineUIContainer>
<TextBlock Text="Caption text" FontSize="18" Foreground="White" />
</InlineUIContainer>
</TextBlock>
</l:CustomPanel>
As you might have already guessed, what i'd like my code to do is to set my Caption property from XAML on a custom panel, if this is possible.
I've also tried the same code with a DependencyProperty to no avail.
So, anyone that can help me with this problem?
I can explain what is going wrong and how to fix it.
First,
<l:CustomPanel>
<l:CustomPanel.Caption Text="Caption text" FontSize="18" Foreground="White" />
is a simple syntax error. The <l:CustomPanel.Caption> syntax does not accept XML attributes - the property value must be within the element.
This is proper property element syntax:
<l:CustomPanel>
<l:CustomPanel.Caption>
<TextBlock Text="Caption text" FontSize="18" Foreground="White" />
</l:CustomPanel.Caption>
</l:CustomPanel>
but:
Property element syntax works only with DependencyProperties (so it didn't work with your CLR property) and
Property element syntax always honors the ContentPropertyAttribute of the property type
Since TextBlock has a [ContentPropertyAttribute("Inlines")], the property element syntax is trying to add the TextBlock to the Inlines collection.
The solution is simple: Declare your property as a DependencyProperty of type UIElement instead of type TextBlock. This has the additional advantage of not restricting the display of content to just a TextBlock. If you really do want to restrict it to just a TextBlock, you can use a validation callback.
public UIElement Content { get { ...
public static readonly DependencyProperty ContentProperty = ...
Just got a non-ideal workaround from a colleague of mine. It involves declaring the Caption property as a resource like:
<Page.Resources>
<TextBlock x:Key="test" Text="Caption text" FontSize="18" Foreground="White" />
</Page.Resources>
<l:CustomPanel Caption="{StaticResource test}" />
I'd still like to know why I can't use the two previous options, so if anyone knows please answer. :)
It seems that you can get this error (in Silverlight 4 and 5 at least) if you specify a namespace on the element. For example:
<Path>
<MapLayer.Position xmlns="clr-namespace:Microsoft.Maps.MapControl">
...
In this case MapLayer.Position is an attached property. It seems that the Silverlight parser requires the namespace to be defined using a prefix:
<Path xmlns:map="clr-namespace:Microsoft.Maps.MapControl">
<map:MapLayer.Position>
...

Categories

Resources