I have a listbox that is populated from a datatable. I want each item to have a specific image on listbox, but I want to set the image depending of an id that each item has.
for example , I have :
Products
Orange
Apple
ID
1
2
and the images are named: Item.1.png , Item.2.png
So, in my listbox,where I have apple, I will have next to it the image named: Item.2.png.
My problem is that I don't know how could I do a conditional binding . I don't want to have on my template hundreds of lines that are doing this for each item. I need to do this using a condition, like : if(product.id==1), Image.Source=Item.1.png.
Is there any way to do this in wpf?
It sounds to me like you need an IdToImageConverter that will decides which Image should be shown dependant on the value of the Id property. Something like this should do the trick:
[ValueConversion(typeof(int), typeof(ImageSource))]
public class IdToImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value.GetType() != typeof(int) || targetType != typeof(ImageSource)) return false;
int id = (int)value;
if (id < 0) return DependencyProperty.UnsetValue;
string imageName = string.Empty;
switch (id)
{
case 1: imageName = "Item.1.png"; break;
case 2: imageName = "Item.2.png"; break;
}
if (imageName.IsEmpty()) return null;
return string.Format("/AppName;component/ImageFolderName/{0}", imageName);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
You could then use it in your ListBox.ItemTemplate something like this:
<YourConvertersXmlNamespacePrefix:IdToImageConverter x:Key="IdToImageConverter" />
...
<ListBox ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Id, Converter={StaticResource
IdToImageConverter}}" />
<TextBlock Text="{Binding Name}" Margin="5,0,0,0" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
As I understand your question, every object in the listbox has an ID property, where you want the image to be item.ID.png.
You could use a converter in your binding to do this. So in your listbox template, you can have something like:
// ... Listbox template
<Image Source={Binding pathToItemID, Converter={StaticResource MyConverter}/>
// ... Remaining ListBox template
You will need to add the converter to the UserControl's resources:
<UserControl.Resources>
<xmlnsPointingToConverter:MyConverter x:Key="MyConverter"/>
</UserControl.Resources>
Then add a MyConverter class which implements IValueConverter:
public class MyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return string.Format("item.{0}.png", value);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Related
What I want it to bind TextBoxes to my dictionaries values.
I could find some posts about it already but :
One means having my dictionary as context :
XML :
<TextBox x:Name="FirstLine" Text="{Binding Path=[FirstLine]}"/>
XAML :
public ImportProfilesOptions()
{
InitializeComponent();
contexte = new ViewModelImportProfilesOptions();
DataContext = contexte.ParamsData;
}
The other one using Templates :
<ItemsControl x:Name="dictionaryItemsControl" ItemsSource="{Binding dictionary}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Key}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
But I would like to use it, without using Templates (I need to add in labels some translates I take from properties), and without setting my dictionary as context. Something like that :
XML
<TextBox x:Name="FirstLine" Text="{Binding Path=ParamsDate[FirstLine]}" />
XAML
contexte = new ViewModelImportProfilesOptions();
DataContext = contexte;
But then, binding is not working anymore.
You can't do this out of the box, though you could create your own converter I guess:
public class SomeFunkyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is Dictionary<string,string> dictionary))
return null;
if (!(parameter is string key))
return null;
return !dictionary.TryGetValue(key, out var result) ? null : result;
}
// ill leave this up to you
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
=> throw new NotSupportedException();
}
Usage
<TextBlock Text="{Binding Path=ParamsDate,
ElementName=TextBox,
Converter={StaticResource SomeFunkyConverter},
ConverterParameter='Bob'}"/>
Note : Completely untested
I want to join a list and bind them within a TextBlock in a GridView (or ListView) block.
Let me draw a picture to explain the scenario.
C#
I have a list of StudentInfo which contains Name (string), ID (int) and Courses (List<string)
XAML
<ListView.ItemTemplate>
<DataTemplate x:DataType="data:StudentInfo">
<StackPanel>
<TextBlock Text="{x:Bind StudentName}" Margin="1"/>
<TextBlock Text="{x:Bind ID}" Margin="1"/>
<!--In the following textblock, I want to show something like this
"Taken Courses Are - PHY, CHM, MAT"-->
<TextBlock Text="{x:Bind Courses}" Margin="1"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
In the last TextBlock I want to join all the courses a student have taken and show them with a hard coaded text -
"Taken Courses Are - ".
How can I do that?
you can simply use a IValueConverter to Bind list
<TextBlock Text="{x:Bind Courses,Converter={StaticResource ListToStringConverter}}" Margin="1"/>
Here the Converter
public class ListToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, string language)
{
return String.Join(", ", ((List<string>)value).ToArray());
}
public object ConvertBack(object value, Type targetType,
object parameter, string language)
{
throw new NotImplementedException();
}
}
Edit
Add ListToStringConverter to your resources
<Page.Resources>
<local:ListToStringConverter x:Name="ListToStringConverter" ></local:ListToStringConverter>
</Page.Resources>
Write a converter class to covert your list to a comma separated string.
XAML code
<TextBlock Text="{Binding Path=Courses,Converter={StaticResource CourseToStringConverter}}" Margin="1"/>
CourseToStringConverter
[ValueConversion(typeof(List<string>), typeof(string))]
public class CourseToStringConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (targetType != typeof(string))
throw new InvalidOperationException("The target must be a String");
return "Taken Courses Are - " + String.Join(", ", ((List<string>)value).ToArray());
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
I have one Enum Description Converter
public class EnumDescriptionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
//// parameter need current item, but null or "Value"
if (Enum.IsDefined(value.GetType(), value) == false)
return System.Windows.DependencyProperty.UnsetValue;
string parameterString = Enum.GetName(value.GetType(), value);
if (parameterString == null)
return System.Windows.DependencyProperty.UnsetValue;
var desc = (value.GetType().GetField(parameterString).GetCustomAttributes(typeof(DescriptionAttribute), false).FirstOrDefault() as DescriptionAttribute);
if (desc != null)
return desc.Description;
else
return parameter.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
i like to Pass current combobox item to converter as ConverterParameter
<ComboBox Name="test" Grid.Column="1" Grid.Row="2" VerticalAlignment="Center" IsReadOnly="True" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource enumDescriptionConverter},ConverterParameter=Value}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
but Value is coming as string "Value", when i try binding getting error. Is any way to pass current item ?
You don't need a converter parameter for this. Simply replace:
value.GetType().GetField(parameterString)
with
value.GetType().GetField(value.ToString())
You can get rid of parameterString entirely. The string representation of a singular enum value always matches the field name for that value (or, in cases where multiple enum elements have the same value, it will match the field name for an equivalent value).
I am working on a windows universal app and I'm trying to work out data binding.
I have a listview which has an item template and data template in which a property of a custom class is bound.
<ListView>
<ListView.ItemTemplate>
<DataTemplate>
<Textblock Text="{Binding Name}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This works fine an displays the names all instances of my custom class in the ObservableCollection I bind to the listview. I was wondering however if there is some way of modifying what is being bound before it is bound without changing the class itself.
I'm trying to bind a capitalisation of the string property Name so if the name was Test I want to bind TEST instead. Currently the way I'm doing this is to have a separate property called NameLabel which I populate like this
NameLabel = Name.ToUpper();
However this seems very messy and I was wondering if there's a neater way of doing it without creating a separate property?
You can use a Converter.
Create a StringToUpper.cs File with a StringToUpper Class which inherits form IValueConverter:
public class StringToUpper: IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
var valueString = value.ToString();
if (!string.IsNullOrEmpty(valueString))
{
return valueString.ToUpper();
}
return string.Empty;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
// do nothing.
}
}
Add the resource of your created Converter:
...
xmlns:converter="clr-namespace:StringToUpper"
...>
<Window.Resources>
<converter:StringToUpper x:Key="StringToUpperConverter" />
</Window.Resources>
Add the converter:
<Textblock Text="{Binding Name, Converter={StaticResource StringToUpperConverter}}"/>
Here is a good Tutorial about Converters in WPF.
You could create a converter, that turns the value of a property into a form desired for the view (in your case, a simple capitalisation of the string).
Your converter class might look like this:
public class StringToUpperStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var valueString = value.ToString();
if (!string.IsNullOrEmpty(valueString))
{
return valueString.ToUpper();
}
return string.Empty;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Your xaml might have this defined in the resource section:
<converters:StringToUpperStringConverter x:Key="StringToUpperStringConverter" />
And your binding would then look like this:
<Textblock Text="{Binding Name, Converter={StaticResource StringToUpperStringConverter}}"/>
Hear i Have a confusion while Binding the data to Text Block in Windows phone
I have Text Block
<TextBlock Name="strytxt"
Text="{Binding STORY}"
Height="auto"
Width="Auto"
TextWrapping="Wrap"/>
in STORY Object some time I have Empty/Null Values
At that Time im Getting Some space in my UI
Now i Want to Make Visibility of the Textbox in to Collapsed if i get Null in that row
How can i do this
To change the Visibility of the TextBlock when the Binding value is null you need to use a Converter that converts from null/not null to Visible/Collapsed.
HereĀ“s a converter that converts the values. The converter handles an empty string as null, so that it return Collapsed for string.empty.:
public class NullToVisibilityConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
bool isVisible = value == null ? false : true;
if (isVisible) {
string stringValue = value as string;
if (stringValue != null) {
isVisible = string.IsNullOrEmpty(stringValue) ? false : true;
}
}
if (System.ComponentModel.DesignerProperties.IsInDesignTool) {
return Visibility.Visible;
}
return isVisible ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();
}
}
You can apply the converter to the TextBlock as follows:
<UserControl.Resources>
<local:NullToVisibilityConverter x:Key="NullToVisibilityConverter"/>
</userControl.Resources>
<TextBlock Name="strytxt"
Visibility="{Binding STORY, Converter={StaticResource nullToVisibilityConverter}}"/>
Another alternativ is to display a Text when the value is null, you can specify that in the binding
<TextBlock Name="strytxt"
Text="{Binding STORY, TargetNullValue='is Null'}"/>
You can use a value converter to convert the value to a visibility:
public class NullToVisibiltyConverter : IValueConverter {
public Object Convert(Object value, Type targetType, Object parameter, CultureInfo culture) {
return value == null ? Visibility.Collapsed : Visibility.Visible;
}
public Object ConvertBack(Object value, Type targetType, Object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}
You then bind the Visibility of the TextBlock using the converter:
<TextBlock Name="strytxt"
Text="{Binding STORY}"
Height="auto"
Width="Auto"
TextWrapping="Wrap"
Visibility="{Binding STORY, Converter={StaticResource NullToVisibilityConverter}}"/>
You need to add an instance of the converter to a resource dictionary to be able to reference it in the binding:
<UserControl.Resources>
<local:NullToVisibilityConverter x:Key="NullToVisibilityConverter"/>
</userControl.Resources>