WPF Binding to a function return - c#

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();
}
}

Related

Redraw DataTemplate of ContentControl

I have the following ContentControl:
<ContentControl
Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SelectedEntry}">
<ContentControl.ContentTemplate>
<DataTemplate DataType="controls:HCITextListEntry">
<controls:MyCustomControl
Text="{Binding Text}"
Parameter="{Binding Parameters}"/>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
Everytime the SelectedEntry property changes, I want to redraw/reinit MyCustomControl. Actually only the properties are updated.
You may drop the ContentTemplate and write a converter for the Content Binding that returns a MyCustomControl instance:
<ContentControl Content="{Binding SelectedEntry,
RelativeSource={RelativeSource TemplatedParent},
Converter={StaticResource MyCustomControlConverter}}"/>
The converter:
public class MyCustomControlConverter : IValueConverter
{
public object Convert(
object value, Type targetType, object parameter, CultureInfo culture)
{
var control = new MyCustomControl();
control.SetBinding(MyCustomControl.TextProperty,
new Binding("Text") { Source = value });
control.SetBinding(MyCustomControl.ParameterProperty,
new Binding("Parameters") { Source = value });
return control;
}
public object ConvertBack(
object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}

Converter Parameter In ItemTemplate

I have a collection of Checkboxes in a Listbox binding to an Enum which uses a converter. Code shown below:
<ListBox HorizontalAlignment="Left" Height="183" Margin="159,30,0,0" VerticalAlignment="Top" Width="144">
<ListBox.Resources>
<local:FlagsEnumValueConverter x:Key="FlagsConverter" />
</ListBox.Resources>
<CheckBox Content="Checkbox1" IsChecked="{
Binding Path=TestModel.TestEnum,
Converter={StaticResource FlagsConverter},
ConverterParameter={x:Static tc:TestEnum.Test1}}"/>
<CheckBox Content="Checkbox2" IsChecked="{
Binding Path=TestModel.TestEnum,
Converter={StaticResource FlagsConverter},
ConverterParameter={x:Static tc:TestEnum.Test2}}"/>
<CheckBox Content="Checkbox3" IsChecked="{
Binding Path=TestModel.TestEnum,
Converter={StaticResource FlagsConverter},
ConverterParameter={x:Static tc:TestEnum.Test3}}"/>
</ListBox>
Converter Code:
class FlagsEnumValueConverter : IValueConverter
{
private int mTargetValue;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var mask = (int)parameter;
mTargetValue = (int)value;
return ((mask & mTargetValue) != 0);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
mTargetValue ^= (int)parameter;
return Enum.Parse(targetType, mTargetValue.ToString());
}
}
I'd rather use an ItemTemplate to keep things clean and simple however I'm not sure what to do with the 'ConverterParameter' since it requires the specific Enum value. I've been Googling for a solution but haven't found one. I honestly don't even know where to start. Is this even possible?

XAML binding list enum

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;
}
}

WPF Binding to Radio Buttons If Radio Buttons duplicated to same property .,.,. not updating the Model

Here This is the View which the Radio buttons had been bound to a Enum Property using IValueConverter(Works Fine)
if I duplicate these radio Buttons as Below XAML
<Grid.Resources>
<l:enumBoolConverter x:Key="ebc" />
<l:EnumStringConverter x:Key="es" />
</Grid.Resources>
<StackPanel>
<StackPanel>
<RadioButton IsChecked="{Binding YesOrNo, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource ebc}, ConverterParameter=Yes}">Yes</RadioButton>
<RadioButton IsChecked="{Binding YesOrNo, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource ebc}, ConverterParameter=No}">No</RadioButton>
<RadioButton IsChecked="{Binding YesOrNo, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource ebc}, ConverterParameter=Maybe}">Maybe</RadioButton>
<Separator />
<TextBox Text="{Binding YesOrNo, Converter={StaticResource es}, Mode=OneWay}" />
</StackPanel>
<StackPanel>
<RadioButton IsChecked="{Binding YesOrNo, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource ebc}, ConverterParameter=Yes}">Yes</RadioButton>
<RadioButton IsChecked="{Binding YesOrNo, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource ebc}, ConverterParameter=No}">No</RadioButton>
<RadioButton IsChecked="{Binding YesOrNo, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource ebc}, ConverterParameter=Maybe}">Maybe</RadioButton>
<Separator />
<TextBox Text="{Binding YesOrNo, Converter={StaticResource es}, Mode=OneWay}" />
</StackPanel>
</StackPanel>
I can do Changing option From "Yes" to "No" but While am changing From "No" to "Yes" there is the problem which the property or view will not be updated..
Why..
I guess it,, for the second radio button of the "No" Option was once again called to Set the property "YesOrNo" while I am changing the First to "Yes"
is it so.. ??? What is the Resolution to Operate both the group... to one property.. and get updated on all the bindings.. ?
The CS Code for Value Convertions
[ValueConversion(typeof(YesOrNoOptions), typeof(bool))]
class enumBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var ps = parameter as string;
if (string.IsNullOrEmpty(ps))
return DependencyProperty.UnsetValue;
if (!Enum.IsDefined(typeof(YesOrNoOptions), value))
return DependencyProperty.UnsetValue;
var param = Enum.Parse(value.GetType(), ps);
var ret = param.Equals(value);
return ret;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var ps = parameter as string;
if (string.IsNullOrEmpty(ps))
{
return DependencyProperty.UnsetValue;
}
return Enum.Parse(targetType, ps);
}
}
[ValueConversion(typeof(YesOrNoOptions), typeof(string))]
internal class EnumStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Enum v = (Enum)value;
return v.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
CS Code of ViewModel
public enum YesOrNoOptions
{
Yes,
No,
Maybe
}
public class DemDC : INotifyPropertyChanged
{
public DemDC()
{
_yt = YesOrNoOptions.Yes;
}
public YesOrNoOptions _yt;
public YesOrNoOptions YesOrNo
{
get
{
return _yt;
}
set
{
_yt = value;
Notify("YesOrNo");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void Notify(string pname)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(pname));
}
}
Thanks in Advance...
Any how the logic should be same for all the views isn't it?
While coming from "yes" to "No" both the panels are updated fine..
but while going back to "Yes" from "No" it stays there in the "No" option itself..
because the second radio button is setting the "No" value to enum... ??? while operating "Yes" isn't it???
if this is happening..? Why it is not happening while choosing from "Yes" to "No" ?????
To circumvent this issue you can disable property changes while the property is being updated:
private bool suppress;
private YesOrNoOptions _yt;
public YesOrNoOptions YesOrNo
{
get
{
return _yt;
}
set
{
if (_yt != value && !suppress)
{
_yt = value;
suppress = true;
Notify("YesOrNo");
suppress = false;
}
}
}

Hierarchical Data Template of an object with a property as List<AnotherObject>

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>

Categories

Resources