WPF StringFormat databinding text not appearing - wpf

I am trying to get the header text of a TreeviewItem to be set in the binding to an XML source. Everything is working fine except the only thing that appears in the header is the text I'm binding to and nothing else in the string format. Example:
<HierarchicalDataTemplate x:Key="LogDataTemp" ItemsSource="{Binding Path=log}">
<TreeViewItem>
<TreeViewItem.Header>
<Binding Path="Attribute[level].Value" StringFormat="TEST \{0\}" />
</TreeViewItem.Header>
</TreeViewItem>
</HierarchicalDataTemplate>
In this case the level value appears but nothing else. I have tried dozens of different ways of approaching this and it seems that nothing works.

Don't escape the braces in the StringFormat. You want to apply the formatting to the 0th-element in your binding.
For instance, with a simple property called "Level":
<TextBlock x:Name="txtUnformatted" Grid.Row="0" Foreground="White" >
<TextBlock.Text>
<Binding Path="Level" />
</TextBlock.Text>
</TextBlock>
<TextBlock x:Name="txtFormatted" Grid.Row="1" Foreground="White">
<TextBlock.Text>
<Binding Path="Level" StringFormat="Test {0:000000}" />
</TextBlock.Text>
</TextBlock>
And the result is something like:
Update
Also, the default implementation of the Header, when you don't add any controls, is a simple ContentPresenter, which doesn't apply formatting. To work around this, simply put a TextBlock into the header, and bind the text you want formatted to that.
<HierarchicalDataTemplate x:Key="LogDataTemp" ItemsSource="{Binding Path=log}">
<TreeViewItem>
<TreeViewItem.Header>
<TextBlock>
<TextBlock.Text>
<Binding Path="Attribute[level].Value"
StringFormat="TEST {0}" />
</TextBlock.Text>
</TextBlock>
</TreeViewItem.Header>
</TreeViewItem>
</HierarchicalDataTemplate>
It is perfectly acceptable (and commonly done) to put controls into a header control (for instance, a grid containing an image and a label). The beauty of WPF.

Related

Display different values in ComboBox based on a conditional from converter

I have a ComboBox which should display different values based on a condition.
If the SelectedValue's properties Name or Email is not null and is not empty I want to display those.
If above is not true I want to fallback and display the SelectedValue's Username, this is never null or empty.
This is what I have so far.
<ctrls:RadComboBoxExtended Grid.Row="0" Grid.Column="1" ItemsSource="{Binding CurrentValue.LIST_OF_USERS}" SelectedValue="{Binding CurrentValue.User}" focus:FocusExtension.IsFocused="{Binding Focuspoint}">
<ctrls:RadComboBoxExtended.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Visibility>
<MultiBinding Converter="{StaticResource MultiNullOrEmptyStrToVisibility}" ConverterParameter="1">
<Binding Path="Name"/>
<Binding Path="Email"/>
</MultiBinding>
</TextBlock.Visibility>
<Run Text="{Binding Name}"/>
<Run Text="("/><Run Text="{Binding Email}"/><Run Text=")"/>
</TextBlock>
</DataTemplate>
</ctrls:RadComboBoxExtended.ItemTemplate>
</ctrls:RadComboBoxExtended>
Above XAML displays all users which have a Name and Email correctly.
How would I go about displaying the "else branch" for this? As of now the users which do not meet the condition of my converter is blank in the ComboBox. How can I display those?
Simplest way is to surround TextBlock with StackPanel or Grid and put also another TextBlock there, setting ConverterParameter="10" and handling it so, that only one of TextBlocks will be visible.
Another possibility is to use ItemTemplateSelector to define which DataTemplate should be used if RadComboBoxExtended has such a property.
<ctrls:RadComboBoxExtended Grid.Row="0" Grid.Column="1" ItemsSource="{Binding CurrentValue.LIST_OF_USERS}" SelectedValue="{Binding CurrentValue.User}" focus:FocusExtension.IsFocused="{Binding Focuspoint}">
<ctrls:RadComboBoxExtended.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock>
<TextBlock.Visibility>
<MultiBinding Converter="{StaticResource MultiNullOrEmptyStrToVisibility}" ConverterParameter="1">
<Binding Path="Name"/>
<Binding Path="Email"/>
</MultiBinding>
</TextBlock.Visibility>
<Run Text="{Binding Name}"/>
<Run Text="("/><Run Text="{Binding Email}"/><Run Text=")"/>
</TextBlock>
<TextBlock Text="{Binding Username}">
<TextBlock.Visibility>
<MultiBinding Converter="{StaticResource MultiNullOrEmptyStrToVisibility}" ConverterParameter="10">
<Binding Path="Name"/>
<Binding Path="Email"/>
</MultiBinding>
</TextBlock.Visibility>
</TextBlock>
</StackPanel>
</DataTemplate>
</ctrls:RadComboBoxExtended.ItemTemplate>
</ctrls:RadComboBoxExtended>
I would put the choice between name+email vs username in the ViewModel. (One of ViewModel responsibilities is to provide data for View in a convenient format)
public string SelectionText => String.IsNullOrEmpty(Name) && String.IsNullOrEmpty(Email)
? Username
: $"{Name} ({Email})" ;
much shorter DataTemplate and MultiValueConverter is not required
<ctrls:RadComboBoxExtended Grid.Row="0" Grid.Column="1" ItemsSource="{Binding CurrentValue.LIST_OF_USERS}" SelectedValue="{Binding CurrentValue.User}" focus:FocusExtension.IsFocused="{Binding Focuspoint}">
<ctrls:RadComboBoxExtended.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding SelectionText}"/>
</DataTemplate>
</ctrls:RadComboBoxExtended.ItemTemplate>
</ctrls:RadComboBoxExtended>

binding Textblock from two textboxex value in Xaml

I have two textbox txtFName and txtLName . Now I want to display txtFName - txtLName in textblock using binding.
For bind only txtFName I write below code:
<TextBlock x:Name="textblock" Text="{Binding ElementName=txtFName , Path=Text}" Margin="-3,-8,0,0"/>
But I want to display txtFName - txtLName in textblock using binding.
I do not want to write any code in code behind.
Thanks,
You can do that using MultiBinding:
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} - {1}">
<Binding ElementName="txtFName" Path="Text"/>
<Binding ElementName="txtLName" Path="Text"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
The content of a TextBlock is composed of a collection of inline objects, e.g. Runs. Therefore, you can bind txtFName and txtLName to two different runs, e.g. like this:
<TextBlock x:Name="textblock">
<Run Text="{Binding ElementName=txtFName, Path=Text}"/>
<Run Text=" - "/>
<Run Text="{Binding ElementName=txtLName, Path=Text}"/>
</TextBlock>

Binding Row to Validation Rule WPF

I want to bind TextBox's Tag (which is inside a DataGrid), to validation rule's CurrentLegStrategy property (which is a DependencyProperty). Although I've done something similar with Deal dependency property using a global tunnel object, however not able to figure out, what would be the tunnel for CurrentLegStrategy (ideally should be coming from the bound data to DataRow or to the bound data to TextBox's tag)?
<DataTemplate x:Key="PremiumProp">
<TextBlock Style="{StaticResource TextBlockLeft}" Tag="{Binding Strategy}" x:Name="txtPremiumProp">
<TextBlock.Text>
<Binding Path="AbsolutePremium" StringFormat="{}{0:#,##0.00####}" Converter="{StaticResource _DoubleConvertor}">
<Binding.ValidationRules>
<Control:MBSStrategyBasedDoubleValidation ValidatesOnTargetUpdated="True" ValidationTag="premabs"
ErrorMessage="Please enter a valid positive (+) premium (also check the reference which is required for auto calculation)!">
<Control:MBSStrategyBasedDoubleValidation.Deal>
<Control:DealObject Deal="{Binding Tag, Source={StaticResource TradeTunnel}}" CurrentLegStrategy="{Binding Path=Tag, ElementName=txtPremiumProp}"/>
</Control:MBSStrategyBasedDoubleValidation.Deal>
</Control:MBSStrategyBasedDoubleValidation>
</Binding.ValidationRules>
</Binding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
Then I also tried,
<TextBlock.Resources>
<ResourceDictionary>
<FrameworkElement x:Name="strategySource" Tag="{Binding Tag, Source={x:Reference txtPremiumProp}}"/>
</ResourceDictionary>
</TextBlock.Resources>
With the following:
CurrentLegStrategy="{Binding Path=Tag, Source={StaticResource strategySource}}"
Cannot find resource named 'strategySource'. Resource names are case sensitive.

How do you insert a binding into the middle of a sentence of a TextBlock in WPF?

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
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>
The best way of doing it is using the Runs...
<TextBlock>
<Run Text="Welcome"/>
<Run Text="{Binding UserName}"/>
<Run Text="!"/>
</TextBlock>
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.
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.
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

XAML - Binding to DataContext and using converter?

To bind to the current DataContext in XAML you can use:
<TextBlock Text="{Binding}" />
How do you do this using a converter in the mix?
The following works when you have a property on the path:
<TextBlock Text="{Binding MyProperty,Converter={StaticResource converter}}" />
But I dont want to do that; I just want to Bind to the datacontext and not the datacontext.MyProperty if you get what I mean.
Simply omit the path:
<TextBlock Text="{Binding Converter={StaticResource converter}}" />
Ah wait - I notice your question is tagged with Silverlight. Does this not work in Silverlight? If not, you may need to use the expanded syntax:
<TextBlock>
<TextBlock.Text>
<Binding Converter="{StaticResource converter}" />
</TextBlock.Text>
</TextBlock>
Dot sign also provide DataContext Binding for SL developers
<TextBlock Text="{Binding Path=.,Converter={StaticResource converter}}" />

Resources