I'm binding an SqlMoney type to a TextBox in WPF and I'm trying to put digits after decimal point into superscript. This is what I've got so far:
<TextBlock>
<Run FontSize="50">1000</Run>
<Run BaselineAlignment="TextTop" TextDecorations="Underline" FontSize="26">00</Run>
</TextBlock>
Is there a simple way to this in WPF using something like StringFormat or I need to split it somewhere else in code and then bind?
Edit:
Ok, I might have explained it badly. This is actual implementation in code right now:
Model property
public SqlMoney Price { get; }
View
<TextBlock Text="{Binding Mode=OneWay, Path=Price}" />
Effect:
Effect - before and after
Is there way to make View handle splitting or I need to change implementation in Model or VM?
When you use binding, you can use StringFormat to do what you need. In your example there is no binding so no place for StringFormat.
Here is a StringFormat you can use when binding:
StringFormat={}{0:00.00}
Example of binding with StringFormat (assuming Superscript is a property of you DataContext):
<TextBlock>
<Run FontSize="50">1000</Run>
<Run BaselineAlignment="TextTop" TextDecorations="Underline" FontSize="26" Text="{Binding Superscript, StringFormat={}{0:00.00}}"/>
</TextBlock>
If you don't have yet the DataContext set up and you want a self contained example you could create a Resource and bind to it:
<TextBlock>
<TextBlock.Resources>
<sys:Double x:Key="Superscript">0</sys:Double>
</TextBlock.Resources>
<Run FontSize="50">1000</Run>
<Run BaselineAlignment="TextTop" TextDecorations="Underline" FontSize="26" Text="{Binding Source={StaticResource Superscript}, StringFormat={}{0:00.00}, Mode=OneWay}"/>
</TextBlock>
In this example I had to use OneWay binding because I'm binding to a static resource.
Result:
Related
I want binding Text in Tooltip but i have one problem, it is binding value is other element controls, therefore i cannot basically get their value through binding.
<TextBlock x:Name="txb2" Text="Hello Stackoverflow"/>
<TextBox Grid.Row="1" TextChanged="TextBox_TextChanged">
<TextBox.ToolTip>
<TextBlock>
<Run Text="{Binding ElementName=txb2, Path=Text}" FontWeight="Bold"/>
</TextBlock>
</TextBox.ToolTip>
</TextBox>
basically I tried binding this code.
If you look at the output you will see an error:
System.Windows.Data Error: 4 : Cannot find source for binding with
reference 'ElementName=txb2'. BindingExpression:Path=Text;
DataItem=null; target element is 'Run' (HashCode=58577354); target
property is 'Text' (type 'String')
You can fix it by using x:Reference:
<TextBlock x:Name="txb2" Text="Hello Stackoverflow"/>
<TextBox Grid.Row="1">
<TextBox.ToolTip>
<TextBlock>
<Run Text="{Binding Source={x:Reference txb2}, Path=Text}" FontWeight="Bold"/>
</TextBlock>
</TextBox.ToolTip>
</TextBox>
As for the difference between ElementName and x:Reference take a look at the following thread. ElementName does not work since Tooltip is not a Ui property, but ElementName only works with Ui Element hierarchy (Visual Tree) when it searches txb2.
Tooltips exist outside the visual tree, so can't reference other controls by name. All that a tooltip knows about is its own PlacementTarget – the UIElement that it is displayed against.
One way to allow the tooltip to reference other controls is to hijack some otherwise unused property of this placement target control (Tag is most often suitable), which can then be referenced by the tooltip.
<TextBox x:Name="txb2" Text="Hello Stackoverflow" Width="200" />
<TextBox Grid.Row="1" Tag="{Binding ElementName=txb2}" Width="200">
<TextBox.ToolTip>
<ToolTip DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<TextBlock>
<Run Text="{Binding Text}" FontWeight="Bold" />
</TextBlock>
</ToolTip>
</TextBox.ToolTip>
</TextBox>
if you're using the MVVM design pattern, an alternative method (that doesn't require property hijacking) is to bind to the PlacementTarget's DataContext (usually the ViewModel). You can then bind the tooltip's content to whatever property of that you like.
<ToolTip DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
....
<TextBlock FontSize="20" Foreground="{x:Bind ????}">
<Run Text="{x:Bind Username}"></Run>
<Run Text=": "></Run>
<Run Text="{x:Bind Message}"></Run>
</TextBlock>
That is the TextBlock. My expectation is when the textblock get the string inside the combobox it will set the foreground through that string
<ComboBox
x:Name="CBBox"
PlaceholderText="Color"
Margin="10"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<x:String>Red</x:String>
<x:String>Yellow</x:String>
<x:String>Green</x:String>
<x:String>Purple</x:String>
<x:String>Back</x:String>
</ComboBox>
but I dont know what to bind any idea ?
Foreground="{Binding ElementName=CBBox,Path=SelectedItem}"
<ComboBox
x:Name="CBBox"
PlaceholderText="Color"
Margin="10"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<x:String>Red</x:String>
<x:String>Yellow</x:String>
<x:String>Green</x:String>
<x:String>Purple</x:String>
<x:String>Back</x:String>
</ComboBox>
<TextBlock FontSize="20" Foreground="{Binding ElementName=CBBox,Path=SelectedItem}">
<Run Text="{x:Bind Username}"></Run>
<Run Text=": "></Run>
<Run Text="{x:Bind Message}"></Run>
</TextBlock>
Usually, the best approach is to bind the ComboBox to the view model, and then bind the view model to the TextBlock.
However, it's possible to bind them directly, provided they're in the same scope (Page, UserControl, Template, etc.). You'll have to use {Binding} here, instead of {x:Bind}, since this you'll need a converter.
You can bind the Foreground property like this:
<TextBox Foreground="{Binding SelectedItem, ElementName=CBBox, Converter={StaticResource StringToColorConverter}" ... />
Now you'll need to add a ValueConverter, and get it to convert the selected string to a brush and return it.
Something like this should work:
var colorEnum = (Colors) Enum.Parse(typeof(Colors), value);
var color = new Color(colorEnum);
return new SolidColorBrush(color);
I have a listbox I want to display information in, I bring in variables from a text file and assign them to strings. I want the end result to look like this:
"Make: " [Make] "\t" "Model: " [Model]
"Price: " [Price] "\t" "Mileage: " [Mileage]
I have read into the best options, I am using a ToString method at the moment, however I have read up that templates in the XAML would be a better option.
My question: How do I format a datatemplate in the XAML to display the above information and bring in the variables needed?
It'd look something like this:
<ListBox ItemsSource="{Binding MyList}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text="Make: "/>
<Run Text="{Binding Make}"/>
<Run Text="Model: "/>
<Run Text="{Binding Model}"/>
<Run Text="Price:" />
<Run Text="{Binding Price}"/>
<Run Text="Mileage:" />
<Run Text="{Binding Mileage}"/>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Assuming you have an observable collection of MyList built up from your file, which has properties of Make, Model, etc.
Given your structure here, you may want to consider a ListView (like a list but with columns) rather than a list.
I have got multiple TextBlocks whose Text is inserted through DynamicResource. They are all set to TextWrapping="Wrap". But inside those Text-strings I have words which are not allowed to be split up. Those words must be kept as a whole word.
With hardcoded Text in Xaml it's quite easy solved via a TextBlock inside a Textblock:
<TextBlock TextWrapping="Wrap">
Example text with wrap and <TextBlock TextWrapping="NoWrap" Text=" example text without wrap"/
</TextBlock>
But this solution does not work when Text the is inserted through DynamicResource, because the text is not getting parsed.
How can I combine nowrap and wrap inside a DynamicResource Text without splitting it into multiple TextBlocks one after another?
PS: I have now created an example to demonstrate the behavior I would like (green) and the failed attempts (red, orange, darkred) of solving it:
<StackPanel HorizontalAlignment="Center" Width="80" Orientation="Vertical">
<TextBlock TextWrapping="Wrap" Foreground="green">
bla1 bla2 bla3 bla4 <TextBlock TextWrapping="NoWrap" Text="Together(en)"/> bla5 bla6 longWordWhichShouldBreak
</TextBlock>
<TextBlock TextWrapping="Wrap" Foreground="red">
bla1 bla2 bla3 bla4 Together(en) bla5 bla6 longWordWhichShouldBreak
</TextBlock>
<TextBlock TextWrapping="Wrap" Foreground="orange">
bla1 bla2 bla3 bla4 Together(en) bla5 bla6 longWordWhichShouldBreak
</TextBlock>
<TextBlock TextWrapping="WrapWithOverflow" Foreground="DarkRed">
bla1 bla2 bla3 bla4 Together(en) bla5 bla6 longWordWhichShouldBreak
</TextBlock>
</StackPanel>
Use NO-BREAK SPACE in your dynamic text. For example:
<TextBlock TextWrapping="Wrap">
Example text with wrap and example text without wrap
</TextBlock>
You can replace space with this char in those parts that you need this behaviour:
Replace(" ", System.Convert.ToChar(160))
Have you considered using 'WrapWithOverflow' instead of 'Wrap'?
This will only break the line if a space appears.
You can then set the words that must appear together with dashes,e.g.-
'regular line and words-that-shouldn't-break'
You should use Run:
<TextBlock>
<Run Text={x:static SomeText} />
<Run Text={x:static SomeNoWrapText}
TextWrapping="NoWrap"/>
<Run Text={x:static SomeMoreText} />
</TextBlock>
It's a bit much for a comment, but also not a complete answer.
Lets translate your example piece of XAML from all the implicit contents to a full qualified structure.
Your simplified XAML, using the implicit content properties and so on:
<TextBlock TextWrapping="Wrap" Foreground="green">
bla1 bla2 bla3 bla4 <TextBlock TextWrapping="NoWrap" Text="Together(en)"/> bla5 bla6 longWordWhichShouldBreak
</TextBlock>
Equivalent actual structure:
<TextBlock TextWrapping="Wrap" Foreground="green">
<TextBlock.Inlines>
<Run Text="bla1 bla2 bla3 bla4 "/>
<InlineUIContainer>
<InlineUIContainer.Child>
<TextBlock TextWrapping="NoWrap" Text="Together(en)"/>
</InlineUIContainer.Child>
</InlineUIContainer>
<Run Text=" bla5 bla6 longWordWhichShouldBreak"/>
</TextBlock.Inlines>
</TextBlock>
This should give you some idea about the complexity of what you have in your XAML. You can't archieve the same result by simply setting the Text property.
Currently I can't answer how to solve this issue, since DynamicResource is not enough information to start transforming into above structure.
You may want to have a look at this question: Data binding the TextBlock.Inlines
Let's say I have two TextBlock on the same page and both binding to the same variable:
<TextBlock Text={Binding [someViewModel].someText}/>
<TextBlock Text={Binding [someViewModel].someText}/>
//someText = "testingText"
I'm wondering if it's possible to have the first textblock to show "tes......" and the second textblock showing "testingText"?
Try this
<StackPanel>
<TextBlock Text="testingtext" MaxWidth="20" TextTrimming="CharacterEllipsis" HorizontalAlignment="Left"></TextBlock>
<TextBlock Text="testingtext" ></TextBlock>
</StackPanel>
output
Make an IValueConverter for one of the bindings which converts the String to the custom format you want.