Label Multibinding With Static - c#

How can I display a x:Static variable in a MultiBinding Label?
<Label>
<Label.Text>
<MultiBinding StringFormat="{}{0} {1}">
<Binding Path="x:Static resources:AppResources.FirstName"/>
<Binding Path="User.FirstName"/>
</MultiBinding>
</Label.Text>
</Label>
Desired result:
First Name: John

Instead of Path, use Source.
<Label>
<Label.Text>
<MultiBinding StringFormat="{}{0} {1}">
<Binding Source="{x:Static resources:AppResources.FirstName}"/>
<Binding Path="User.FirstName"/>
</MultiBinding>
</Label.Text>
</Label>

Related

Pass one Binding and one constant string as parameter

I have a button and want to pass multiple command parameter one being Binding and one is a constant string (in this case a constant string TDS)
I am trying to follow this link: Passing two command parameters using a WPF binding but this is for multibinding. In my case I am using 1 binding and one constant string. I tried the below but it is giving syntax error in VS.
<Button.CommandParameter>
<MultiBinding>
<Binding Path="."/>
<s:String>TDS</s:String>
</MultiBinding>
</Button.CommandParameter>
How do I fix this?
Try this:
<Button.CommandParameter>
<MultiBinding Converter="{StaticResource yourConverter}">
<Binding Path="."/>
<Binding>
<Binding.Source>
<s:String>TDS</s:String>
</Binding.Source>
</Binding>
</MultiBinding>
</Button.CommandParameter>
If your string is defined in resources you can reference it this way:
...
<x.Resources>
<s:String x:Key="stringKey">TDS</s:String>
</x.Resources>
...
<Button.CommandParameter>
<MultiBinding Converter="{StaticResource yourConverter}">
<Binding Path="."/>
<Binding Source="{StaticResource stringKey}" />
</MultiBinding>
</Button.CommandParameter>
As mentioned in the comment a converter must be specified for MultiBinding.

ConvertBack is not called

I'm trying to write a universal control in which I can pass different data models (all implement INotifyPropertyChanged) with a converter. The data is passed in the control without problems and is displayed correctly (some of it also uses IMultivalueConverts, which work flawlessly). Although the data is modified, the IMultiValueConverter of the MainControl is not called.
The universal control should just show rectangles calculated from coordinates in an ObservableCollection.
I put DebugConverters on all bindings, and everything seems to be updated except the ConvertBack to the top. The SourceUpdate from the ListBox is also called.
I tried this converter with different NotifyOn...Updated, Mode and UpdateSourceTrigger, I always see the values changing in the control, but never the ConvertBack of the Main Control.
The partial data template used (Updates are done correctly), all the DegreeTo... converters are called both ways
<DataTemplate x:Key="RectangleWithLabel">
<Canvas IsHitTestVisible="True">
<Rectangle x:Name="RectangleROI" MouseLeftButtonDown="myCanvas_PreviewMouseLeftButtonDown" >
<!--
<Rectangle.Visibility>
<Binding Path="ROI" Converter="{StaticResource NullToVisibilityConverter}"/>
</Rectangle.Visibility>
-->
<Canvas.Left>
<MultiBinding Converter="{StaticResource DegreeToScreenPixelConverterH}" Mode="TwoWay" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged" >
<Binding Path="ROI.Begin.PosH" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" />
<Binding Path="DataContext.UsedCoordinateSystem" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}" NotifyOnSourceUpdated="True" Mode="TwoWay" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged" />
</MultiBinding>
</Canvas.Left>
<Canvas.Top>
<MultiBinding Converter="{StaticResource DegreeToScreenPixelConverterV}" Mode="TwoWay" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged">
<Binding Path="ROI.Begin.PosV" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" />
<Binding Path="DataContext.UsedCoordinateSystem" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}" NotifyOnSourceUpdated="True" Mode="TwoWay" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged"/>
</MultiBinding>
</Canvas.Top>
<Rectangle.Width>
<MultiBinding Converter="{StaticResource DegreeToScreenPixelWidthConverter}" Mode="TwoWay" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged">
<Binding Path="ROI.Begin.PosH" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" />
<Binding Path="ROI.End.PosH" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" />
<Binding Path="DataContext.UsedCoordinateSystem" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}" NotifyOnSourceUpdated="True" Mode="TwoWay" NotifyOnTargetUpdated="True"/>
</MultiBinding>
</Rectangle.Width>
<Rectangle.Height>
<MultiBinding Converter="{StaticResource DegreeToScreenPixelHeightConverter}" Mode="TwoWay" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged">
<Binding Path="ROI.Begin.PosV" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True"/>
<Binding Path="ROI.End.PosV" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" />
<Binding Path="DataContext.UsedCoordinateSystem" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}" NotifyOnSourceUpdated="True" Mode="TwoWay" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged"/>
</MultiBinding>
</Rectangle.Height>
<Rectangle.Fill>#33FF0000</Rectangle.Fill>
<Rectangle.Stroke>#FF00FF00</Rectangle.Stroke>
<Rectangle.IsHitTestVisible>true</Rectangle.IsHitTestVisible>
</Rectangle>
The List View containing all the data:
<ListView ItemsSource="{Binding Rectangles, Mode=TwoWay, NotifyOnTargetUpdated=True, NotifyOnSourceUpdated=True, NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" x:Name="listBox" Width="{Binding ActualWidth, ElementName=ImageControl, Mode=OneWay,UpdateSourceTrigger=PropertyChanged}" Height="{Binding ActualHeight, ElementName=ImageControl, Mode=OneWay,UpdateSourceTrigger=PropertyChanged}" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="{x:Null}" ItemTemplate="{StaticResource RectangleWithLabel}" MouseMove="ListBox_MouseMove" DataContextChanged="ListBox_DataContextChanged" SourceUpdated="ListBox_SourceUpdated" IsSynchronizedWithCurrentItem="True" TargetUpdated="ListBox_TargetUpdated" />
The call to the ImageViewer from the parent, here the converter is called on the way to the ImageViewer, but the ConvertBack is never called:
<common:ImageViewer x:Name="ctrlImage" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<common:ImageViewer.DataContext>
<MultiBinding Converter="{StaticResource ConverterWhichIsOnlyCalledOneWay}" Mode="TwoWay" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged">
<Binding Path="." UpdateSourceTrigger="PropertyChanged" Mode="TwoWay" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True"/>
</MultiBinding>
</common:ImageViewer.DataContext>
</common:ImageViewer>
How can I get the ConvertBack to be called?
EDIT:
I made an overview of the controls and the converters. I think I was wrong, that the ConvertBack should be called, everything is updating, even without the big converter. But I'm still stuck when adding some elements to the ObservableCollection. When I add some values, the values appear in the DataContext of the MainWindow. But the Converter is not triggered. When I add the Observable.Count as Binding to the Big Converter, the update is triggered, but all bindings are lost.
Changes from the original code were: Changing all internal variables to DependencyProperties, this made updates reliable for the single entries in the ObservableCollection.
Overview of the GUI and the used converters
Time to answer the question myself:
I was wrong when assuming that a changes travels down throught the converter when there is a direct connection between two elements.
So if I have an element (just consider it as a leave of a tree) in a deeply nested and it is once displayed once through a converter (which changes some other objects) and the same time without a converter, the element is updated without calling the converter. WPF is so clever to see that the value is the same and does not pipe the change through the converter up and down.

How to put Converter Culture in multibinding on textblock

I usually bind the textblock with string format and converter culture like this:
<TextBlock Text="{Binding CurrentPurchase.SubTotal, StringFormat='{}{0:C}', ConverterCulture='nl-NL'}"/>
But I have a multi binding with string format also that (price x quantity)
How can i put the ConverterCulture='nl-NL' here?
<TextBlock.Text >
<MultiBinding StringFormat='{}{0} x {1}'>
<Binding Path="Price"/>
<Binding Path="Quantity" />
</MultiBinding>
</TextBlock.Text>
Thank you
You can set it on the MultiBinding:
<TextBlock.Text >
<MultiBinding StringFormat='{}{0} x {1}' ConverterCulture="nl-NL">
<Binding Path="Price"/>
<Binding Path="Quantity" />
</MultiBinding>
</TextBlock.Text>
unless you need different cultures for Price and Quantity!

Programmaticaly How to provide consecutive arbitary number of whitespace characters within MultiBinding StringFromat?

Please examine following code snippet :
<TextBox x:Name="TxtBox_CommandInfo" Style="{DynamicResource MetroTextBox}" IsReadOnly="True" Controls:TextBoxHelper.Watermark="This is a textbox" HorizontalAlignment="Left" Margin="0,236,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="154" Width="780" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto">
<TextBox.Text>
<MultiBinding StringFormat="{}{0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10}
{11}">
<Binding Path="No" />
<Binding Path="SelectedType" />
<Binding Path="IgnoreSignature"/>
<Binding Path="IgnoreRelString"/>
<Binding Path="DirectDL"/>
<Binding Path="LegacySC" />
<Binding Path="SelectedDVName"/>
<Binding Path="SelectedHCName"/>
<Binding Path="SelectedSCName"/>
<Binding Path="SCRelease"/>
<Binding Path="DALName"/>
<Binding Path="PreviousLogs"/>
</MultiBinding>
</TextBox.Text>
</TextBox>
Here I had to hard-code number of consecutive white-space characters whenever I wanted to format the spaces between bind parameters.
Using (Code for white-space) ,Can we format the string in programmatical/convenient manner(with tricky code) rather than hard-coding(typing) repetitive characters(number of consecutive white spaces that we want).
My assumption like :
<MultiBinding StringFormat="{}{0}[ ,4]{1}[ ,8]{2}{3}{4}[ ,6]{5}{6}[ ,10]{7}{8}{9}{10}
{11}"
Therefore is there any valid mechanism under WPF/XAML MultiBinding StringFormat to provide that, for a given character or set of characters "How many number of consecutive characters or how many repetition of characters should be generated ?"
Means Rather than typing required white spaces like this:
<MultiBinding StringFormat="{}{0} {1} {2}" />
Alternative/Programmatical/Convenient but assumed mechanism(to provide how many number of whitespaces we want) like this:
<MultiBinding StringFormat="{}{0}[Character/s,Number of Repetition]{1}[Character/s,Number of Repetition]{2}" />
<!-- Assumed code like -->
<MultiBinding StringFormat="{}{0}[&#x20,8]{1}[&#x20,10]{2}" />
Thank you!
You can add a whitespace argument and pad it:
<MultiBinding StringFormat="{}{0}{12,5}{1}{12,5}{2}{12,1}{3}{12,1}{4}{12,1}{5}{12,4}{6}{12,8}{7}{12,8}{8}{12,8}{9}{12,4}{10}
{11}">
<Binding Path="No" />
<Binding Path="SelectedType" />
<Binding Path="IgnoreSignature"/>
<Binding Path="IgnoreRelString"/>
<Binding Path="DirectDL"/>
<Binding Path="LegacySC" />
<Binding Path="SelectedDVName"/>
<Binding Path="SelectedHCName"/>
<Binding Path="SelectedSCName"/>
<Binding Path="SCRelease"/>
<Binding Path="DALName"/>
<Binding Path="PreviousLogs"/>
<Binding Path="SomeBindingPathThatDoesNotExist" FallbackValue=" "/>
</MultiBinding>
{12} would be your value (the fallback value which is a space), and you can pad it with {12,x}
A better yet solution would be padding each of the bindings. That gives you a fixed size for each binding (doesn't add a constant number of whitespaces), but it's usually what you want:
<MultiBinding StringFormat="{}{0,10}{1,10}{2,8}(etc.)">
<Binding Path="No" />
<Binding Path="SelectedType" />
<Binding Path="IgnoreSignature"/>
<Binding Path="IgnoreRelString"/>
<Binding Path="DirectDL"/>
<Binding Path="LegacySC" />
<Binding Path="SelectedDVName"/>
<Binding Path="SelectedHCName"/>
<Binding Path="SelectedSCName"/>
<Binding Path="SCRelease"/>
<Binding Path="DALName"/>
<Binding Path="PreviousLogs"/>
</MultiBinding>

StringFormat and Multibinding with Label

I would like to use StringFormat to do someting like this :
<Label x:Name="myLabel">
<Label.Content>
<Multibinding StringFormat="{}{0} - {1}">
<Binding Path="Lib1" />
<Binding Path="Lib2" />
</MultiBinding>
</Label.Content>
</Label>
However, it's doesn't work and I got this error instead :
MultiBinding failed because it has no valid Converter. MultiBindingExpression:target element is 'Label' (Name='myLabel'); target property is 'Content' (type 'Object')
Is there any way to make this code work ?
You cant bind this because you are trying to bind a string to an object which wont work because StringFormat requires its target to be a string type. You can get around this by either using a TextBlock instead (which has a Text property) or putting the Textblock as the child of the Label:
<Label x:Name="myLabel">
<Label.Content>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} - {1}">
<Binding Path="Lib1" />
<Binding Path="Lib2" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Label.Content>
</Label>
For those wondering you can also leave the <Label.Content> tag from Leom Burke's answer. This saves another two lines of code.
<Label x:Name="myLabel">
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} - {1}">
<Binding Path="Lib1" />
<Binding Path="Lib2" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Label>
<Label>
<AccessText>
<MultiBinding StringFormat="{x:Static properties:Resources.MyText}">
<Binding Path="MyObj.MyProp" Mode="OneTime"/>
</MultiBinding>
</AccessText>
</Label>
Where Resources.MyText can hold anything like "Fox jumps over {0}."

Categories

Resources