class EnumToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return loai.ToDisplaytring();
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
<ListView ItemsSource="{Binding ListEnum" Margin="0,51,0,0">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=.,Converter={StaticResource EnumToStringConverter}}" HorizontalAlignment="Center" FontSize="18"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I am a new guy to XAML.
I just want to display enum in listview.
But it has some problem of binding itself with binding:
{Binding Path=.,Converter={StaticResource EnumToStringConverter}}
This is simpler:
<ListView x:Name="ListViewInstance" ItemsSource="{Binding ListEnum}" Margin="0,51,0,0">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" HorizontalAlignment="Center" FontSize="18"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
That's the binding that gets the items, it automatically makes the item.ToString()
and to show all the values in the DataContext, for instance:
public List<Devices> ListEnum { get { return typeof(Devices).GetEnumValues().Cast<Devices>().ToList(); } }
In case you need a converter do the following:
public class EnumToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return what you need to convert from value
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
and then in XAML
<Window.Resources>
<local:EnumToStringConverter x:Key="EnumToStringConverter"/>
</Window.Resources>
<ListView x:Name="ListViewInstance" ItemsSource="{Binding ListEnum}" Margin="0,51,0,0">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding, Converter={StaticResource EnumToStringConverter}}" HorizontalAlignment="Center" FontSize="18"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
You can use the enum with attributes and the create a list for listbox using extension methods.You can refer the below code.
<ListBox Width="200" Height="25" ItemsSource="{Binding ComboSource}"
DisplayMemberPath="Value"
SelectedValuePath="Key"/>
public class MainViewModel
{
public List<KeyValuePair<RentStatus, string>> ComboSource { get; set; }
public MainViewModel()
{
ComboSource = new List<KeyValuePair<RentStatus, string>>();
RentStatus re=RentStatus.Active;
ComboSource = re.GetValuesForComboBox<RentStatus>();
}
}
public enum RentStatus
{
[Description("Preparation description")]
Preparation,
[Description("Active description")]
Active,
[Description("Rented to people")]
Rented
}
public static class ExtensionMethods
{
public static List<KeyValuePair<T, string>> GetValuesForComboBox<T>(this Enum theEnum)
{
List<KeyValuePair<T, string>> _comboBoxItemSource = null;
if (_comboBoxItemSource == null)
{
_comboBoxItemSource = new List<KeyValuePair<T, string>>();
foreach (T level in Enum.GetValues(typeof(T)))
{
string Description = string.Empty;
FieldInfo fieldInfo = level.GetType().GetField(level.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes != null && attributes.Length > 0)
{
Description = attributes.FirstOrDefault().Description;
}
KeyValuePair<T, string> TypeKeyValue = new KeyValuePair<T, string>(level, Description);
_comboBoxItemSource.Add(TypeKeyValue);
}
}
return _comboBoxItemSource;
}
}
Related
C# Code-
namespace WPFDataBinding
{
public partial class MainWindow : Window
{
public Person Obj { get; set; }
public MainWindow()
{
InitializeComponent();
Obj = new Person();
List<string> subjects1 = new List<string>();
subjects1.Add("C"); subjects1.Add("C++"); subjects1.Add("C#");
List<string> subjects2 = new List<string>();
subjects2.Add("JAVA"); subjects2.Add("JS"); subjects2.Add("CSS");
Obj.studDetail.Add("Kush", subjects1);
Obj.studDetail.Add("Yash", subjects2);
DataContext = this;
}
public class Person
{
private Dictionary<string, List<string>> StudDetail = new Dictionary<string, List<string>>();
public Dictionary<string, List<string>> studDetail
{
get { return StudDetail; }
set { StudDetail = value; }
}
}
}
}
WPF code------
<ListBox FontSize="20" Height="Auto" Width="Auto" MinHeight="100" MinWidth="100" Background="Gray">
<Label Content="{Binding Obj}">
<Label.ContentTemplate>
<DataTemplate>
<ListBox Height="Auto" FontSize="20" MinHeight="100"
MinWidth="100" Width="Auto" Name="Sub1"
ItemsSource="{Binding studDetail}"/>
</DataTemplate>
</Label.ContentTemplate>
</Label>
</ListBox>
I wrote this code but the result is not what i expected.Do anyone know what to do in this situation? If yes, Plz Help to solve it.
You can use an IValueConverter to change the data in to a usable form.
If you just want all of the strings in the list of strings clumped together in one list, you can use this converter:
public class StudentDetailsConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var data = value as Dictionary<string, List<string>>;
return data.Values.SelectMany(v => v);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
You will have to add this as a resource someplace accessible in your XAML; the Window is one possibility.
<Window.Resources>
<local:StudentDetailsConverter x:Key="StudentDetailsConverter" />
</Window.Resources>
Then change your binding to this:
ItemsSource="{Binding Path=studDetail, Converter={staticResource StudentDetailsConverter}}"
If you want something different, please update your question.
I've got a Observable collection of custom objects and a public dictionary variable.
I would like the "BrandName" attribute to act as the Key for the "Brands" dictionary and bind the colour to the button. How would I go about doing this? The dictionary variable is outside of the class.
C# Code:
private ObservableCollection<BusService> BusServicesGUI;
public Dictionary<String, Brush> Brands;
public MainWindow(Dictionary<String, BusService> busServices)
{
InitializeComponent();
BusServicesGUI = new ObservableCollection<BusService>(BusServices.Values);
lstMachineFunctions.ItemsSource = BusServicesGUI;
lstMachineFunctions.Items.Refresh();
}
C# Class:
public class BusService
{
public string ServiceNumber { get; set; }
public string BrandName { get; set; }
public List<Location> Locations { get; set; }
public BusService(string brandName, string serviceNumber)
{
BrandName = brandName;
ServiceNumber = serviceNumber;
Locations = new List<Location>();
}
}
XAML CODE:
<StackPanel x:Name="ServiceStack">
<ItemsControl x:Name="lstMachineFunctions">
<ItemsControl.ItemTemplate >
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<usercontrols:BusServiceCard/>
<Button Tag="{Binding ServiceNumber}" Background="{Binding Brands[BrandName]}" Height="50" Click="ButtonCl"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
As you can see from the XAML my current attempts have been trying Background="{Binding Brands[BrandName]}" This has however not worked, any help would be much appreciated.
You can use an IValueConverter to pefrom this operation.
public class BrandColorConverter : IValueConverter
{
public Dictionary<String, Brush> Brands = new Dictionary<string, Brush>()
{
{ "brand1", Brushes.Red },
{ "brand2", Brushes.Blue }
};
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (!(value is BusService))
return Binding.DoNothing;
var busService = (BusService)value;
if (!Brands.ContainsKey(busService.BrandName))
return Binding.DoNothing;
return Brands[busService.BrandName];
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
In xaml, add it as a static resuorce:
<Window.Resources>
<local:BrandColorConverter x:Key="BrandColorConverter"/>
</Window.Resources>
And use it in your button:
<Button Tag="{Binding ServiceNumber}"
Background="{Binding Converter={StaticResource BrandColorConverter}}"
Height="50"
Click="ButtonCl"/>
This binding goes to the current element, so the whole BusService object will be passed to the converter.
Hope it solves your problem.
I would strongly advise you to look into MVVM pattern if you are going to use WPF with data binding, as it makes things much more streamlined.
I have a "Checked ListBox", a ListBox with a CheckBox for each of my Items.
In this ListBox I have a List of Players.
<ListBox ItemsSource="{Binding MyPlayers}" SelectedItem="{Binding SelectedPlayer}" Margin="69,51,347.4,161.8">
<ListBox.ItemTemplate>
<DataTemplate>
<ListBoxItem>
<CheckBox IsChecked="{Binding ???}" Content="{Binding Path=Pseudo}" />
</ListBoxItem>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
ViewModel :
public class MainWindowViewModel : BaseViewModel
{
SavingContext MyDatabaseContext;
public ObservableCollection<Player> MyPlayers
{
get
{
return MyDatabaseContext.MyPlayers.Local;
}
}
Tournament _MyTournament;
public Tournament MyTournament
{
get
{
return _MyTournament;
}
set
{
_MyTournament = value;
}
}
public MainWindowViewModel(Tournament myTournament)
{
MyDatabaseContext = new SavingContext();
MyDatabaseContext.MyPlayers.Load();
MyTournament = myTournament;
}
}
I pass in my ViewModel a Tournament, that contains an HashSet of Players called Participants.
I would like to bind my IsChecked properties to the result of MyTournament.Participants.Contains(this) with this being the Player related to the CheckBox. But I can't manage to make it works.
Edit :
I tried to use a Converter, but with no success.
<helper:PlayerToTournamentRegistered x:Key="PlayerToTournamentRegistered" />
<ListBoxItem>
<CheckBox IsChecked="{Binding Converter={StaticResource PlayerToTournamentRegistered}}" Content="{Binding Path=Pseudo}" />
</ListBoxItem>
public class PlayerToTournamentRegistered : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
//Temp test to see if it would work
if (value == null) return false;
return true;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
I get an error each time Provide value on 'System.Windows.Data.Binding' threw an exception
Any Advices ?
So I managed to get it working using a MultiConverter.
The first error that I had was due to the fact that the Mode is by Default Two Way, I only want to have my Converter work OneWay.
I used a MultiBinding to send to my Converter both my ListBoxItem and my Tournament.
My Converter return true or false, and is linked to my CheckBox.IsChecked properties.
List Box :
<ListBox ItemsSource="{Binding MyPlayers}" SelectedItem="{Binding SelectedPlayer}" Margin="69,51,347.4,161.8">
<ListBox.ItemTemplate>
<DataTemplate>
<ListBoxItem>
<CheckBox Content="{Binding Path=Pseudo}" >
<CheckBox.IsChecked>
<MultiBinding Converter="{StaticResource PlayerToTournamentRegistered}" Mode="OneWay">
<Binding />
<Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=Window}" Path="DataContext.MyTournament"/>
</MultiBinding>
</CheckBox.IsChecked>
</CheckBox>
</ListBoxItem>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Converter :
public class PlayerToTournamentRegistered : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if(!(values[0] is Student) || !(values[1] is Tournament))
{
return false;
}
Tournament myTournament = (Tournament)values[1];
Student myPlayer = (Student)values[0];
if (myTournament.Participants.Contains(myPlayer))
return true;
return false;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
I have an object with this structure
public class Parent
{
public string Name {get; set;}
public int ID {get; set;}
public List<Child> Children{set; get;}
public Address HomeAddress {get; set;}
}
I created a hierarchical template for Address, Parent, Children with the ObjectToObservableListConverter
public class ObjectToObservableListConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null)
{
return new ObservableCollection<Graphic> { (value as Graphic) };
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
and PropertyToListConverter
public class PropertyToListConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Type type = value.GetType();
PropertyInfo[] propertyList = value.GetType().GetProperties();
List<object> values =
(from property in propertyList
//where property.GetCustomAttributes(typeof(NotForTreeViewAttribute), false).Count() == 0
select property.GetValue(value, BindingFlags.Default, null, null, CultureInfo.InvariantCulture)).ToList();
return values;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
The templates I created are:
<TreeView ItemsSource="{Binding Path=Parent,
Converter={StaticResource ResourceKey=objectToListConverter},
UpdateSourceTrigger=PropertyChanged}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type en:Parent}"
ItemsSource="{Binding Path=Children}">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="0,4,0,0"
VerticalAlignment="Center"
FontWeight="Bold"
Text="Children" />
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type en:Child}"
ItemsSource="{Binding Converter={StaticResource ResourceKey=propertyToListConvertor}}">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="0,4,0,0"
VerticalAlignment="Center"
FontWeight="Bold"
Text="{Binding Path=ChildName}" />
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type en:Address}"
ItemsSource="{Binding Converter={StaticResource ResourceKey=propertyToListConvertor}}">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="0,4,0,0"
VerticalAlignment="Center"
FontWeight="Bold"
Text="AddressType" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
If I create the template on Parent
and set the ItemsSource Path of the Children Property, I don't Get the remaining properties of Parent.
Or
If I set the ItemsSource as the property of type Parent and user property to list converter i dont get hierarchy of children.
What am I missing?
Please help. Thanks in Advance
I found the solution to the problem.
I changed my converter to set the list property to another custom class which contains only one property of list type and wrote a hierarchical data template for the same.
PropertyToListConverter
public class PropertyToListConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Type type = value.GetType();
PropertyInfo[] propertyList = value.GetType().GetProperties();
List<object> values =
(from property in propertyList
select GetValueOrElementName(value, property)).ToList();
return values;
}
private static object GetValueOrElementName(object value, PropertyInfo property)
{
var propVal = property.GetValue(value, BindingFlags.Default, null, null, CultureInfo.InvariantCulture);
if (property.PropertyType.IsGenericType && propVal != null)
{
Type type = property.PropertyType.GetGenericArguments().FirstOrDefault();
if (type == typeof(Child))
return new EnumerableClass() { Children = propVal as List<Child> };
}
if (propVal != null && !string.IsNullOrEmpty(propVal.ToString()))
return propVal;
return "Property["+ property.Name+"]";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
CustomClass
public class EnumerableClass
{
public string Name { get; set; }
public List<Child> Children
{
get;
set;
}
}
Hierarchical Data template
<HierarchicalDataTemplate DataType="{x:Type en:Parent}"
ItemsSource="{Binding Converter={StaticResource ResourceKey=propertyToListConvertor}}">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="0,4,0,0"
VerticalAlignment="Center"
FontWeight="Bold"
Text="{Binding Path=ParentName}" />
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type ap:EnumerableClass}"
ItemsSource="{Binding Path=Children,UpdateSourceTrigger=PropertyChanged}">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="0,4,0,0"
VerticalAlignment="Center"
FontWeight="Bold"
Text="Children" />
</StackPanel>
</HierarchicalDataTemplate>
I have a table of categories in my database, as below.
Category
categoryId
name
parentId
The parentId links back to itself to form hierarchy.
How do I bind it to a combobox in WPF so that the child elements are indented as appropriate for each level?
XAML:
<ComboBox ItemsSource="{Binding YourItems}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Margin="{Binding Level, Converter={x:Static my:MainWindow.LevelToMarginConverter}}" Text="{Binding Name}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
C#:
class MainWindow {
......
class LevelToMarginConverterClass : IValueConverter {
const int onelevelmargin = 10;
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
int level = (int)value;
return new Thickness(level * onelevelmargin,0,0,0);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
return null;
}
}
public static IValueConverter LevelToMarginConverter = new LevelToMarginConverterClass();
}
Be sure to have int Level and string Name properties in your class