I have the following list binded to a list of bytes:
<ListView ItemsSource="{Binding Payload}" VerticalAlignment="Center" BorderBrush="Transparent">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding StringFormat=0x{0:x2}}" Margin="2,1,2,1" MinWidth="25" MinHeight="20" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"></WrapPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
That Payload is an ObservableCollection. I get the values and display them in hexa but i want this to be a two way mode. At first i get values like 0x00 but i would like to modify that value let's say in 0xff and put that back in the Payload collection like 255.
I think i need a converter but i would need some help in that direction.
As the commenters mentioned, you can use an IValueConverter for that. Try this:
public class ByteToHexadecimalConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null || targetType != typeof(string)) return DependencyProperty.UnsetValue;
byte byteValue = 0;
if (!byte.TryParse(value.ToString(), out byteValue)) return DependencyProperty.UnsetValue;
return byteValue.ToString("x2");
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null || targetType != typeof(byte)) return DependencyProperty.UnsetValue;
string stringValue = value.ToString();
byte returnValue = 0;
try { returnValue = System.Convert.ToByte(stringValue, 16); }
catch { return DependencyProperty.UnsetValue; }
return returnValue;
}
}
You might need to tweak it a bit for your exact requirements, but it's all easily understandable. You can find out more about IValueConverter from the IValueConverter Interface page on MSDN.
Related
I m doing an UWP project and I wan't to format a string using a converter and Static resource String because the application is in mulitple languages.
Here is my converter :
public class StringFormatConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value == null)
return null;
if (parameter == null)
return value;
return string.Format((string)parameter, value);
}
public object ConvertBack(object value, Type targetType, object parameter,
string language)
{
throw new NotImplementedException();
}
}
Here the string in my Resource Strings.Xaml file :
<x:String x:Key="nbItems">You have {0} items...</x:String>
Here the element where I wan't to pass this formatter :
<TextBlock Text="{x:Bind NbItems, Converter={StaticResource StringFormatConverter}, ConverterParameter={StaticResource nbItems}, Mode=OneWay}"/>
It's not working but if I do like this it works :
<TextBlock Text="{x:Bind NbItems, Converter={StaticResource StringFormatConverter}, ConverterParameter='You have {0} items..', Mode=OneWay}"/>
The parameters is always null in my converter, why it's not working ?
Not exactly certain why the parameter is null, however I have come up with a workaround. Move your strings into a Resource file (see here).
Then change the parameter you pass to your converter to the String Name, like so:
<TextBlock Text="{x:Bind NbItems, Converter={StaticResource StringFormatConverter}, ConverterParameter='FORMAT', Mode=OneWay}" />
Finally change your converter to load the the resource using the parameter like so:
public object Convert(object value, Type targetType, object parameter, string language) {
if (value == null)
return null;
var loader = new Windows.ApplicationModel.Resources.ResourceLoader();
var str = loader.GetString((string)parameter);
return string.Format(str, value);
}
Hope this helps.
Using a wpf ListBox I'm trying to display a list of filename without displaying the full path (more convenient for user).
Data comes from an ObservableCollection which is filled using Dialog.
private ObservableCollection<string> _VidFileDisplay = new ObservableCollection<string>(new[] {""});
public ObservableCollection<string> VidFileDisplay
{
get { return _VidFileDisplay; }
set { _VidFileDisplay = value; }
}
In the end I want to select some items and get back the full file path. For this I have a converter :
public class PathToFilenameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
//return Path.GetFileName(value.ToString());
string result = null;
if (value != null)
{
var path = value.ToString();
if (string.IsNullOrWhiteSpace(path) == false)
result = Path.GetFileName(path);
}
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
Which I bind to my listbox itemsource :
<ListBox x:Name="VideoFileList" Margin="0" Grid.Row="1" Grid.RowSpan="5" Template="{DynamicResource BaseListBoxControlStyle}" ItemContainerStyle="{DynamicResource BaseListBoxItemStyle}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemsSource="{Binding Path=DataContext.VidFileDisplay, Converter={StaticResource PathToFileName},ElementName=Ch_Parameters, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding Path=SelectedVidNames,ElementName=Ch_Parameters, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
Without the converter, it is working fine (but of course this is the full path displayed in the listbox). With the converter I have one character per line... displaying this :
System.Collections.ObjectModel.ObservableCollection`1[System.String]
Where am I wrong ?
Thank you
In ItemsSource binding converter applies to the whole list and not to each item in the collection. If you want to apply your converter per item you need to do it ItemTemplate
<ListBox x:Name="VideoFileList" ItemsSource="{Binding Path=DataContext.VidFileDisplay, ElementName=Ch_Parameters}" ...>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=., Converter={StaticResource PathToFileName}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I've got an enum which I use its values as choices in a combo box.
The enum is this:
public enum TimeSizeEnum
{
TENTHSECONDS,
SECONDS,
MINUTES,
HOURS
}
The way I'm binding the values to the combo box:
<ComboBox Grid.Row="4" Grid.Column="1" ItemsSource="{Binding Path=TimeSizeItemsSource, Converter={StaticResource TimerSizeConverter}}" SelectedItem="{Binding Path=TimeSize, Mode=TwoWay}" SelectedIndex="0" Margin="5" MinWidth="100"></ComboBox>
public string[] TimeSizeItemsSource
{
get
{
return Enum.GetNames(typeof(TimeSizeEnum));
}
}
I want that instead of TENTHSECONDS, I'll see "Tenth of a second" or instead of SECONDS, I'll see "Seconds".
How can I achieve that? Is a value converter the best way to do it? But then it means I need to hard-code the strings I want?
I'd recommend using the DescriptionAttribute:
public enum TimeSizeEnum
{
[Description("Tenths of a second")]
TENTHSECONDS,
[Description("Seconds")]
SECONDS,
[Description("Minutes")]
MINUTES,
[Description("Hours")]
HOURS
}
You can then examine the enum value you're passed in a ValueConverter, read the description from the attribute, and display that:
public class TimeSizeEnumDescriptionValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var type = typeof(TimeSizeEnum);
var name = Enum.GetName(type, value);
FieldInfo fi = type.GetField(name);
var descriptionAttrib = (DescriptionAttribute)
Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute));
return descriptionAttrib.Description;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
To apply the value converter to each enum value, you need to change the combo box's ItemTemplate to include the value converter:
<Window.Resources>
<test:TimeSizeEnumDescriptionValueConverter x:Key="converter" />
</Window.Resources>
<!-- ... -->
<ComboBox ItemsSource="{Binding TimeSizeItemsSource}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<ContentPresenter
Content="{Binding Converter={StaticResource converter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
You can put the attributes on your enum members like
public enum TimeSizeEnum
{
[Description("Tenth of a second")]
TENTHSECONDS,
[Description("Seconds")]
SECONDS,
}
and then you can write a converter which read and return these attributes from the value passed i.e in Convert method of your IValueConveter you can write
var enumtype = typeof(TimeSizeEnum);
var memInfo = enumtype.GetMember(value.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute),
false);
var description = ((DescriptionAttribute)attributes[0]).Description;
return description
I'm trying to stylish this ListBox with alternate row colors:
<ListBox x:Name="listBox" Background="{x:Null}" SelectionChanged="listBox_SelectionChanged" >
<ListBox.Resources>
<local:AltBackgroundConverter x:Name="AltBackgroundConverter" />
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0" Height="50" Background="{Binding Converter={StaticResource AltBackgroundConverter}}" >
<TextBlock Text="{Binding Titulo}" Style="{StaticResource ListViewItemTextBlockStyle}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This is the AltBackgroundConverter.cs:
public class AltBackgroundConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (!(value is int)) return null;
int index = (int)value;
if (index % 2 == 0)
return Colors.White;
else
return Colors.Gray;
}
// No need to implement converting back on a one-way binding
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
Obviously, it's not working because I'm not achieving how to bind the row number to the converter. As you can see, I'm binding a entire ListBox Item.
I think the solution should be really simple, but I can't find it.
There are a couple of problems with your solution right now.
Your binding to your list items, while the converter needs an integer to figure out if an item is even or odd. Based on your screenshot you should change it so it looks like this:
Background="{Binding Numero, Converter={StaticResource AltBackgroundConverter}}"
Your converter returns a color, while the Background is a brush, so you could fix it like this:
public class AltBackgroundConverter : IValueConverter
{
private Brush whiteBrush = new SolidColorBrush(Colors.White);
private Brush grayBrush = new SolidColorBrush(Colors.Gray);
public object Convert(object value, Type targetType, object parameter, string language)
{
if (!(value is int)) return null;
int index = (int)value;
if (index % 2 == 0)
return whiteBrush;
else
return grayBrush;
}
// No need to implement converting back on a one-way binding
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
Things should start working at this point, but your highlighting will only highlight the text instead of entire rows. This is how you can fix that up:
<ListBox.ItemContainerStyle>
<Style
TargetType="ListBoxItem">
<Setter
Property="HorizontalContentAlignment"
Value="Stretch"></Setter>
</Style>
</ListBox.ItemContainerStyle>
I just made my first converter to convert from int to string. I have a combobox fill with integers(years) but if the value is 0 I want the combobox to show 'All'.
This is my converter:
public class IntToString : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null)
{
int intY = (int)value;
if (intY == 0)
{
String strY = "All";
return strY;
}
else
{
return intY.ToString();
}
}
return String.Empty;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
}
}
In XAML where should I set the converter ? I tried in the ItemsSource of the combobox:
ItemsSource="{Binding YearsCollection, Converter={StaticResource intToStringYearConverter}}"
But I always get InvalidcastException on this line:
int intY = (int)value;
The problem is that you are trying to convert the entire collection rather than just one item from the collection.
You would want to do something like this:
<ListBox ItemsSource="{Binding YearsCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border DataContext="{Binding Converter={StaticResource intToStringYearConverter}">
...
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You can't use the converter like this, converter in ItemsSource is supposed to convert whole collection, not individual items. The collection object can't be cast to integer, so you get the exception.
You have to use DataTemplate and apply the converter on individual items.
Or - if all you need is cast to int - you could use ItemStringFormat.
Also, for setting the default message when the source is null, you can use TargetNullValue property of a Binding.