I have created a multilingual WPF application using Andre's answer from here. I'm binding text like this
<TextBlock Text="{DynamicResource Create}"/>
and can switch from english to french at runtime - nice! However, this does not work with ItemsSource. For example, I have a ComboBox that should display all available languages:
<ComboBox ItemsSource="{Binding AllLanguages, Source={StaticResource Locator}}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{DynamicResource LanguageId}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Set up like this, the combobox displays no text. If I set the textblock's text inside to Text={LanguageId}, I see the LanguageIds 'eng', 'fr' etc., so the binding works.
When using a converter:
<TextBlock Text="{Binding LanguageId, Converter={StaticResource DynamicResourceConverter}"/>
languages are displayed as "English" and "French". When I switch the language, however, the converter is not called again and the language names are not updated - so that is no real workaround.
I'd be very thankful for a tip on the cause and how to fix this.
I'll explain first why a few things are not working.
....
<DataTemplate>
<TextBlock Text="{DynamicResource LanguageId}"/>
</DataTemplate>
....
This is a short hand for Text="{DynamicResource ResourceKey='LanguageId'}" which is a static string literal and does not involve any binding.
It would be great if the following was available, but unfortunetly is NOT POSSIBLE because the target for the binding is not a DependancyProperty.
....
<DataTemplate>
<TextBlock Text="{DynamicResource ResourceKey={Binding LanguageId}}"/>
</DataTemplate>
....
You are close with your workaround. My suggestion would be to try the following:-
....
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource DynamicResourceConverter}">
<Binding Path="LanguageId"/>
<Binding Path="SomeOtherPropertyThatChangesWhenLanguageIsSwitched" Source="{StaticResource Locator}"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
....
You will need to expand the DynamicResourceConverter to now implement also IMultiValueConverter. In a MultiBinding scenario, if either bound expression changes then the converter is called again. You would write the Converter such that it only operates on values[0] of the supplied object array as the second value is not needed and only provided a trigger for the converter to be called again.
public class DynamicResourceConverter: IValueConverter, IMultiValueConverter
{
....
// original converter implementation for IValueConverter
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
....
}
// newly added converter implementation for IMultiValueConverter
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
//call the original converter method with one value (assuming you've checked the array has at least one item!!
return Convert(values[0], targetType, parameter, culture)
}
....
}
Related
I use in XAML an ItemsControl where and in its ItemsSource I make a Binding for an Enum, thus creating a list of RadRadioButton dynamically, and if someday another item is added to this enumerator my code will already create this new button and show it.
<ItemsControl ItemsSource="{Binding MyEnum}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<telerik:RadRadioButton GroupName="GroupMyEnum">
<TextBlock Text="{Binding Converter={StaticResource EnumDescriptionConverter}}"/>
</telerik:RadRadioButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Today I use a converter that takes the description of the Enum and shows instead of the value of the Enum.
But besides that I would like to change the order in which my list of buttons is generated, is this possible?
Example: If my list needs to be generated elsewhere in the interface, it must be generated in a different order than the enumerator was created.
Whether an Enum has the options A, B, C, D. At one point I would like to show as the first option D instead of A.
Was I clear enough?
Define a converter that takes MyEnum, change its order based on the value of converter's parameter and return the new list with the new order (ConverterParameter is optional, do not set it if you don't want to change the order of the list).
public class MyEnumCollectionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is IEnumerable<MyEnum> input)
{
switch (parameter)
{
case "Case1":
// todo: change the order of input
return input;
case "Case2":
// todo: change the order of input
return input;
}
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Define the converter in your app.xaml (or at one of ItemsControl parents) and use it like this..
<ItemsControl ItemsSource="{Binding MyEnum, Converter={StaticResource MyEnumCollectionConverter}, ConverterParameter=Case1}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<telerik:RadRadioButton GroupName="GroupMyEnum">
<TextBlock Text="{Binding Converter={StaticResource EnumDescriptionConverter}}"/>
</telerik:RadRadioButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Note that you can do the EnumDescriptionConverter work inside MyEnumCollectionConverter, so your TextBlock can be just
<TextBlock Text="{Binding .}"/>
The first thing that pops to mind is sorting the ItemSource itself. I believe you use Linq sort by calling List.Sort() on the source itself and the list of order on the visual layer should be altered aswell.
More information about this can be found here.
I understand the concept of Binding / Value converter well, but for some reasons the following binding doesn't work. I would like the change the FontWeight to Bold for some Descriptions (Description is a text field):
XAML:
<DataGridTextColumn Header="Description"
Binding="{Binding Description}"
FontWeight="{Binding Description, Converter={converters:DescriptionToFontWeightConverter}}"/>
Value converter method (simplified):
public class DescriptionToFontWeightConverter : ConverterMarkupExtension<DescriptionToFontWeightConverter>
{
public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// Some logic based on the value
// ..
return "Bold"; // I believe I should use "Bold", and not "FontWeights.Bold" here (like it would be with a dependency property, but the problem is that it doesn't go inside the method.
}
public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => Binding.DoNothing;
}
I believe the problem comes from the binding path of the FontWeight property. For example, if I replace (Path=)Description by RelativeSource={RelativeSource Self}, it goes inside the value converter method, but I don't think I can retrieve the value of the binding.. I think it isn't something abnormal (at least something I didn't expect), but I wonder if I shouldn't replace the DataGridTextColum by a DataGridTemplateColum and digs further?
I use the ConvertMarkupExtension method from this website which doesn't require to specify the value converters as static resources.
UPDATE with DataGridColumnTemplate
<DataGridTemplateColumn Header="Description">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Description}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontWeight"
Value="{Binding Description, Converter={converters:DescriptionToFontWeightConverter}}"/>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding Description}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
Thanks for any insights :-)
A DataGridColumn doesn't inherit any DataContext so trying to bind to a Description property of the current item will always fail.
The Binding property is special. Its type is Binding and the binding that you define in XAML will eventually be applied to the element that gets created at runtime. In the case of a DataGridTextColumn, this is a TextBlock or a TextBox depending on whether you are in edit mode.
but I wonder if I shouldn't replace the DataGridTextColum by a DataGridTemplateColum and digs further
If you use a DataGridTemplateColumn and define a TextBlock in the CellTemplate (and a TextBox in the CellEditingTemplate), you can actually bind to a property of the current item as usual. This is because the element in the template is added to the element tree and inherits a DataContext like any other element.
I currently have a combobox in my WPF application, but it seems like there's some lag before the value is converted.
The value converter converts a UUID/GUID to a name, but what shows up on the combobox is first the UUID/GUID for a split second and then the name shows up.
Here's a boiled down version of my combobox:
<ComboBox x:Name="MyComboBox"
Text="{Binding Path=GUID, Converter={StaticResource GUIDToNameValueConverter}, Mode=OneWay}"
ItemTemplate="{StaticResource MyTemplate}"
Style="{StaticResource MyStyle}"
ItemsSource="{Binding Source={x:Static myNameSpace:MyItems}, Path=Items}"
SelectionChanged="MyChangedEventHandler">
</ComboBox>
Here's the general gist of my valueconverter:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string GUID = (string)value;
MyObject myObject = GetObjectById(GUID);
return myObject.name;
}
Essentially, I want to get rid of the split second display of the GUID before the actual name shows up. I'm unsure why the GUID event shows up since the converter takes care of converting that to a name.
Let me know if this is enough information to have this question answered, if not, please request more parts of my code!
I have a couple of gauges in my app, and I can't figure out how to add a converter to the text binding. I read a couple of guides on msdn but I didn't manage to figure that out (I've been coding for WP8 for just a couple of weeks).
This is is a piece of the gauge:
<gauges:MarkerGaugeIndicator Value="0"
gauges:LinearGaugeRange.IndicatorOffset="35"
x:Name="GaugeBarValore"
IsAnimated="True">
<gauges:MarkerGaugeIndicator.MarkerTemplate>
<DataTemplate>
<Grid Width="73" Height="35" UseLayoutRounding="False" d:LayoutRounding="Auto" Margin="10,-2,0,0">
<TextBlock x:Name="GaugeBarPercent" Text="{Binding}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="20"
FontWeight="Thin" Margin="6,4,32,4" Width="35"/>
<Grid.RenderTransform>
<CompositeTransform Rotation="90" TranslateX="49" TranslateY="12" />
</Grid.RenderTransform>
</Grid>
</DataTemplate>
</gauges:MarkerGaugeIndicator.MarkerTemplate>
</gauges:MarkerGaugeIndicator>
The binding itself works, but I can see a lot of decimal numbers while the value moves from a round value to another.
I want to add a converter like this method:
private String double2String(double valore)
{
return Convert.ToString(Math.Round(valore)) + "%";
}
I just don't know where to put this method and how to add this as a converter inside the binding.
Thank you for your help! :)
Sergio
Create a class to hold your Converter method that implements IValueConverter interface, Example class is bellow. You have to implement method Convert and ConvertBack.
public class DoubleToString : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Math.Round((double)value).ToString() + "%";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return double.Parse(value as string);
}
}
then add the namespace to your XAML page.
xmlns:convert="clr-namespace:Your_project_name"
Next add your converter as a Resource type i to your XAML page..
<phone:PhoneApplicationPage.Resources>
<convert:DoubleToString x:Key="DoubleConvert" />
</phone:PhoneApplicationPage.Resources>
The x:Key value is the name we are going to call in our binding statement.
Then perform the data binding. I have a simple slider and a textblock with sliders value bound to the textblocks Text property
<StackPanel>
<Slider Name="slider" Maximum="100" Minimum="0" />
<TextBlock Text="{Binding Value, ElementName=slider, Converter={StaticResource DoubleConvert}}" />
</StackPanel>
Define this converter as a resource in your parent view
<UserControl.Resources>
<local:double2String x:Key="convertDouble" />
</UserControl.Resources>
And add it to the binding
<TextBlock x:Name="GaugeBarPercent" Text="{Binding, Converter={StaticResource convertDouble}}"
Don't forget to import the namespace where the converter is defined to your view
xmlns:local="clr-namespace:YOUR_NAMESPACE"
The easier way is to use StringFormat. Like this:
<Label Text="{Binding Path=SomeProperty, StringFormat='{0:F2}%' }"/>
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!