There's this combo box in a WPF application that is populated from an enum.
How would one disable some of its items? Disabling has to be dynamic, based on another property in the ViewModel.
<ComboBox ItemsSource="{utility:EnumMarkupExtension {x:Type types:SomeEnum}}"
SelectedItem="{Binding Path=MySelection, Converter={StaticResource SomeEnumToString}}" />
EnumMarkupExtension is defined thus:
public sealed class EnumMarkupExtension : MarkupExtension
{
public Type Type { get; set; }
public EnumMarkupExtension(Type type) => this.Type = type;
public override object ProvideValue(IServiceProvider serviceProvider)
{
string[] names = Enum.GetNames(Type);
string[] values = new string[names.Length];
for (int i = 0; i < names.Length; i++)
values[i] = Resources.ResourceManager.GetString(names[i]);
return values;
}
}
(SomeEnumToString is an IValueConverter which probably is not relevant to this)
Is there some obvious method of doing this that I'm missing?
I've seen solutions like this
https://www.codeproject.com/Tips/687055/Disabling-ComboboxItem-in-ComboBox-Control-using-C
but can't figure out how to pass a property to IValueConverter since ConverterParameter is not bindable.
I know you have solved the issue with the help of #clemens. Still posting an answer for others who might same question.
Assuming VMDataSource is datasource in Viewmodel and with each item in VMDataSource contains a boolean flag to indicate whether to enable/ disable the item. Following code snippet would work as you queried in the post.
<ComboBox ItemsSource="{Binding VMDataSource}">
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="IsEnabled" Value="{Binding Path="VMDisableItem"/>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
Assuming VMDataSource is datasource in Viewmodel and viewmodel contains a Non-boolean property to indicate whether to enable/ disable the item instead of datasource itself containing a bool property to enable/diasble the item(Incase of enums).
In this case a multibinding and a converter that would take the item in VMDataSource and a
non-boolean property to enable/disable an item as follows
<ComboBox DataContext="{StaticResource viewmodelInstance}"
ItemsSource="{Binding VMDataSource}">
<ComboBox.Resources>
<local:Disabler x:Key="disabler"/>
</ComboBox.Resources>
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="IsEnabled">
<Setter.Value>
<MultiBinding Converter="{StaticResource disabler}">
<!--Here you can bind the proper u want to use in -->
<!--converter to enable/ disable comboboxitem-->
<!--Currently it is bound property of viewmodelInstance that as non-boolean property-->
<Binding
RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType=ComboBox}"
Path="DataContext.VMDisableItem"/>
<!--Bind to the current comboboxitem which needs to enabled/disabled-->
<Binding />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
Assuming typeof(VMDisableItem) and typeof(VMDataSource) are both string.
When both are equal, disable the item otherwise enable.
class Disabler : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return !Equals(values[0], values[1]);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
You can use a multiBinding where one of the values is instead of the ConverterParameter. See this answer
Edit the comboboxitem itemtemplate, in the item template bind IsEnabled with the value of the viewmodel (it should be an index) and converter paraemeter the value of the item itself.
Related
The end goal of my application is for a user to compare 2 DataTables. I have 2 DataGrids displayed side-by-side showing the DataTables, with the rows already rearranged so that any matching rows between the 2 tables are aligned.
My desire is that I want any non-matching rows to have a red background, like this:
I have my XAML set up similar to this question:
<DataGrid Name="comparisonGridLeft" ItemsSource="{Binding}" Margin="3" CanUserResizeRows="False">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding Match}" Value="true">
<Setter Property="Background" Value="Red"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
</DataGrid>
With my DependencyProperty "Match" defined similar to this answer:
public class CustomProperties
{
public static DependencyProperty MatchProperty =
DependencyProperty.RegisterAttached("Match",
typeof(bool),
typeof(CustomProperties),
new PropertyMetadata(null));
public static void SetMatch(DependencyObject obj, bool value)
{
obj.SetValue(MatchProperty, value);
}
public static bool GetMatch(DependencyObject obj)
{
return (bool)(obj.GetValue(MatchProperty));
}
}
My final roadblock is that when I iterate through the DataGrids to set the "Match" property to the correct value, I get an error:
error CS1503: Argument 1: cannot convert from 'System.Data.DataRowView' to 'System.Windows.DependencyObject'
foreach (DataRowView leftRow in leftGrid.ItemsSource)
{
foreach (DataRowView rightRow in rightGrid.ItemsSource)
{
bool foundMatch = DetermineIfMatch(leftRow, rightRow);
if (foundMatch)
{
//Throws the compile-time error
CustomProperties.SetMatch(leftRow, true);
foundCloseMatch = true;
break;
}
}
}
Thanks in advance for any help. New to WPF and have been working on this all day to no avail 😩
You can't use the attached property in this case. This is how you can attack the problem
Define cache, holding non matching datarows
static class CacheService
{
public static readonly HashSet<DataRowView> Cache = new HashSet<DataRowView>();
}
Do the comparison, build cache of differences
HashSet<DataRowView> _cache = CacheService.Cache;
foreach (DataRowView leftRow in leftGrid.ItemsSource)
{
foreach (DataRowView rightRow in rightGrid.ItemsSource)
{
bool foundMatch = DetermineIfMatch(leftRow, rightRow);
if (!foundMatch)
_cache.Add(leftRow);
}
}
Tweak the XAML
<DataGrid Name="comparisonGridLeft" ItemsSource="{Binding}" Margin="3" CanUserResizeRows="False">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Background" Value="{Binding Path=., Converter={StaticResource MatchToBrushConverter}}" />
</Style>
</DataGrid.RowStyle>
</DataGrid>
The converter
public class MatchToBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
HashSet<DataRowView> _cache = CacheService.Cache; //Get the cache
return _cache.Contains(value) ? Brushes.Red : Brushes.Transparent;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
FYI, I've not tested it.
Hope this helps.
You can't set an attached property on a DataRowView since as you see, it's not a DependencyObject which is a requirement for attached properties. What is the binding source for the DataGrids? If you control that object, you could stick the Match property in that object.
Just a side note... to me, your loop could just set the background color, there isn't really a need for an attached property.
EDIT: from the sound of things, I wouldn't get the data in a data table, but rather your own POCO:
class MyPoco
{
string PropA {get;set}
string PropB {get;set}
Color Background {get;set}
}
Then have a List<MyPoco> and set the ItemsSource to that. Instead of auto binding, you'd have to define the columns yourself and bind those to the POCO properties:
<DataGrid ItemsSource={Binding Pocos}>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding PropA}" />
Now you can add your styling property to the POCO, the Background property. Then you would define a DataGrid.RowStyle that sets the Background by binding to the Background property.
Today I found something strange (for me). If I want to update a DataGrid through a property in my ViewModel the Binding wont get notified. The special think here is (I think) the Binding is bound to another object (part of an Collection) not directly the property i change.
I have prepared some sample code for you. But first a little (Depper) explanation.
Of course it is just a sample but here I have a ViewModel with two public Properties (Items and CurrentItem). Items is a ObservableCollection and serves as the ItemsSource of my DataGrid. CurrentItem is a String which serves as indicator for a converter to set the background colour (for the grid).
I add two instances o String to my Collection and after the program is started the behaviour is as expected. The first line is green the second is white (set through the converter and the properties).
But if I change the value of CurrentItem after the program was loaded (lets say through the button) the colours wont update on my Datagrid.
If I create a breakpoint at the beginning of the converter I can see (after the loading process) the converter wont execute again so it has to be a Problem with the Binding. I think the problem is my property which is not part of the items in my Collection. The OnPropertyChange method seems to not trigger the update for the RowStyle properly.
In real life the model class of the collections is not a string and the model class implements INotifyPropertyChange (but I don´t think this is the problem cause i just don´t update anything in the model).
I need this kind of behaviour to visible highlight more rows based on a dynamic indicator (similar to the example). If no one knows a better way I think I will implement some kind of Property in my models and update the property with a method from the ViewModel.
ViewModel:
public class MainWindowViewModel : INotifyPropertyChanged
{
public static MainWindowViewModel instance = null;
private string _CurrentItem;
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string Property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(Property));
}
}
public string CurrentItem
{
get
{
return _CurrentItem;
}
set
{
if (value != _CurrentItem)
{
_CurrentItem = value;
OnPropertyChanged("CurrentItem");
OnPropertyChanged("Items");
}
}
}
public ObservableCollection<String> Items { get; set; }
public MainWindowViewModel()
{
instance = this;
Items = new ObservableCollection<string>();
CurrentItem = "First";
Items.Add("First");
Items.Add("Second");
Items.Add("First");
}
View XAML
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Window.Resources>
<local:StringToColorConverter x:Key="StringToColorConverter" />
</Window.Resources>
<DockPanel Margin="30">
<Button DockPanel.Dock="bottom" Content="From First to Second" Click="Button_Click" />
<DataGrid IsReadOnly="True" ItemsSource="{Binding Items}" ColumnWidth="*" AutoGenerateColumns="False">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Background"
Value="{Binding Converter={StaticResource StringToColorConverter}}" />
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="Text" Binding="{Binding}" />
</DataGrid.Columns>
</DataGrid>
</DockPanel>
Converter
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var item = value as string;
if (item == MainWindowViewModel.instance?.CurrentItem)
return "Green";
return "White";
}
So sorry for the long post I hope you can comprehend my problem and of course maybe help me :)
You can involve CurrentItem using an IMultiValueConverter
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Background">
<Setter.Value>
<MultiBinding Converter="{StaticResource MultiStringToColorConverter}">
<Binding />
<Binding Path="DataContext.CurrentItem"
RelativeSource="{RelativeSource FindAncestor,
AncestorType={x:Type Window}}"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</DataGrid.RowStyle>
The Converter
public class MultiStringToColorConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
var item = values[0] as string;
var current = values[1] as string;
if (item == current)
return new SolidColorBrush(Colors.Green);
return new SolidColorBrush(Colors.White);
}
public object[] ConvertBack(object values, Type[] targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Everything is normal !
It is by design.
Your background is bound to the n-th object of the DataGrid.
It is not bound to CurrentItem, so there is no reason the binding updates the n-th line background.
Because you have an ObservableCollection, you could put a IsSelected property in MyItem class
And you should make MyItem rà ise a PropertyChanged event on IsSelected property.
Of course MyItem would implement INotifyPropertyChanged
Last, you should change the binding :
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Background"
Value="{Binding Path=IsSelected,
Converter={StaticResource BooleanToColorConverter}}" />
</Style>
</DataGrid.RowStyle>
Of course changing the StringToColorConverter into BooleanToColorConvert wouldbe trivial.
Regards
I have a tabcontrol like this:
<TabControl>
<local:TabItem x:Name="son" Header="son">
<local_son:SonView />
</local:TabItem>
<local:TabItem x:Name="daughter" Header="daughter">
<local_daughter:DaughterView />
</local:TabItem>
</TabControl>
There is a button in DaughterView, I want to click this button to switch to
son tab. My questions is how can I reach to tabindex of son tab in the DaughterView?
Thank you in advance!
Seems kinda odd to have a button inside of a tab switch to another tab. I would think that would be a toolbar button or something like that. I.e. outside of the tab. But if you insist :)... I'd use the messenger / event aggregator pattern and post an event and have the view subscribe and switch the tab. I wouldn't have the child view do it byitself.
You need to bind "SelectedIndex" to a property in your view model. I personally like keeping things type-safe and able to be unit-tested, so when I need to manipulate TabControls in code I usually start by declaring an enum with one value for each tab:
public enum MyTabs : int
{
[Description("Tab 1")]
Tab1,
[Description("Tab 2")]
Tab2,
[Description("Tab 3")]
Tab3
}
The description attribute is the text I want displayed in the tab header, more on that in a moment. My view model contains a member of type MyTabs which is updated whenever the user clicks a tab and which I can also set manually myself via code:
public class MyViewModel : ViewModelBase
{
private MyTabs _CurrentTab;
public MyTabs CurrentTab
{
get { return this._CurrentTab;}
set { this._CurrentTab = value; RaisePropertyChanged(() => this.CurrentTab); }
}
}
Now you need to bind your TabControl to this property:
<TabControl
ItemsSource="{Binding Source={StaticResource MyTabs}}"
SelectedIndex="{Binding CurrentTab, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<TabControl.Resources>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Header" Value="{Binding Path=., Converter={StaticResource EnumDescriptionConverter}}" />
</Style>
</TabControl.Resources>
</TabControl>
Unfortunately WPF binding isn't smart enough to work with integer enums, so I'm also using a converter to cast between enums and integers:
public class EnumToIntConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (int)value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return Enum.ToObject(targetType, value);
}
}
There are a few other things going on here...first of all you'll notice that I'm not actually declaring the TabItems anywhere. That's because I'm generating them automatically from the Enum values themselves; if I add a new value to the MyTab enum then a tab for it magically appears! In this case I'm binding to a static resource with the key "MyTabs", that's a ObjectDataProvider that enumerates the values in my enum:
<ObjectDataProvider x:Key="MyTabs" MethodName="GetValues" ObjectType="{x:Type sys:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:MyTabs"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
This raises the question of how the tabs know what to display in their headers and on the tabitem content areas. The headers use the "Description" attribute declared in the enum, the code for the EnumDescriptionConverter is on another page on this site. To specify the content for each page I create a ControlTemplate for each of my enum values and key it to the enum value itself. A data template is then used to select the appropriate one to use for each tab:
<Window.Resources>
<ControlTemplate x:Key="{x:Static local:MyTabs.Tab1}">
<TextBlock Text="This is the first tab" />
</ControlTemplate>
<ControlTemplate x:Key="{x:Static local:MyTabs.Tab2}">
<TextBlock Text="This is the second tab" />
</ControlTemplate>
<ControlTemplate x:Key="{x:Static local:MyTabs.Tab3}">
<TextBlock Text="This is the third tab" />
</ControlTemplate>
<DataTemplate DataType="{x:Type local:MyTabs}">
<ContentControl>
<ContentControl.Template>
<MultiBinding Converter="{StaticResource ResourceKey=BindingToResourceConverter}">
<Binding RelativeSource="{RelativeSource AncestorType={x:Type Window}}" Path="Resources" />
<Binding />
</MultiBinding>
</ContentControl.Template>
</ContentControl>
</DataTemplate>
</Window.Resources>
The final piece of the puzzle is the BindingToResourceConverter which simply takes a binding (i.e. one of the enum values) and uses it to look up the appropriate ControlTemplate:
public class BindingToResourceConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (values[0] as ResourceDictionary)[values[1]];
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
And that's it! Every time I want to add a new page to a TabControl I simply add a value to it's corresponding enum and create a ContentControl key'd to that value. Everything else happens automatically, and best of all it's both type-safe and unit-testable.
I have an application developed in WPF using the MVVM pattern (MVVM Light Toolkit).
So far, I had no problems, until it is time to change at runtime the style associated with some of my controls, a set of MenuItems. (They can have up to three different styles).
If I was not working with MVVM I could solve it using the command:
MenuElement_Left4.Style = (Style)FindResource("MenuButtonTabsLeft");
But because I want do it completely in MVVM, I've done these tests to achieve that:
1) Try to change the style with a binding (this has not worked):
<MenuItem x:Name="MenuElement_Left4" Header="Test" Style="{Binding SelectedStyle}">
And in the ViewModel:
public string SelectedStyle
{
get { return this.selectedStyle; }
set { this.selectedStyle = value;
RaisePropertyChanged("SelectedStyle");
}
}
private string selectedStyle;
2) Change the style with DataTrigger (this has not worked too. Raises an exception (Style Trigger to Apply another Style)):
<MenuItem.Style>
<Style TargetType="{x:Type MenuItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=TestStyle}" Value="True">
<Setter Property="Style" Value="{StaticResource MenuButtonTabsLeftArrow}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=TestStyle}" Value="False">
<Setter Property="Style" Value="{StaticResource MenuButtonTabsLeft}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.Style>
At the end, I managed to solve it, using a Combox using the following code (I only use the ComboBox to change the style of the MenuItems so it is invisible). Got the idea from (How can I change an elements style at runtime?):
<MenuItem x:Name="MenuElement_Left4" Header="Test" Style="{Binding ElementName=AvailableStyles, Path=SelectedItem.Tag}">
<ComboBox Name="AvailableStyles" SelectedIndex="{Binding AvailableStylesIndex}" Visibility="Collapsed">
<ComboBoxItem Tag="{x:Null}">None</ComboBoxItem>
<ComboBoxItem Tag="{StaticResource MenuButtonTabsLeftArrow}">MenuButtonTabsLeftArrow</ComboBoxItem>
<ComboBoxItem Tag="{StaticResource MenuButtonTabsLeft}">MenuButtonTabsLeft</ComboBoxItem>
</ComboBox>
And in my ViewModel:
public int AvailableStylesIndex
{
get { return this.availableStylesIndex; }
set
{
this.availableStylesIndex = value;
RaisePropertyChanged("AvailableStylesIndex");
}
}
I'd rather use a cleaner way. Any suggestions? A piece of code would be very helpful.
Since you are keeping your styles in you resources, cleaner approch would be to use IMultiValueConverter's with you first approch something like this:
ViewModel
public string SelectedStyle
{
get { return this.selectedStyle; }
set { this.selectedStyle = value;
RaisePropertyChanged("SelectedStyle");
}
}
private string selectedStyle;
Xaml:
<MenuItem.Style>
<MultiBinding Converter="{StaticResource StyleConverter}">
<MultiBinding.Bindings>
<Binding RelativeSource="{RelativeSource Self}"/>
<Binding Path="SelectedStyle"/>
</MultiBinding.Bindings>
</MultiBinding>
</MenuItem.Style/>
In the converter find the style you want and apply it
class StyleConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
FrameworkElement targetElement = values[0] as FrameworkElement;
string styleName = values[1] as string;
if (styleName == null)
return null;
Style newStyle = (Style)targetElement.TryFindResource(styleName);
if (newStyle == null)
newStyle = (Style)targetElement.TryFindResource("MyDefaultStyleName");
return newStyle;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Taken out from Steven Robbins's answer in this post
I have a radio button group in a listview. The rows of this listview (which contain the radio button grp amongst other things) is an observable collection.
the code I have written goes something like this:
The Xaml:
<RadioButton Content="EnumValueName1"
GroupName="RadButGrp1"
IsChecked="{Binding propertyName,Mode=TwoWay,Converter={StaticResource EnumToBoolConverter},ConverterParameter=EnumValueName1}" >
</RadioButton>
<RadioButton Content="EnumValueName2"
GroupName="RadButGrp1"
IsChecked="{Binding propertyName,Mode=TwoWay,Converter={StaticResource EnumToBoolConverter},ConverterParameter=EnumValueName2}">
</RadioButton>
<RadioButton Content="EnumValueName3"
GroupName="RadButGrp1"
IsChecked="{Binding propertyName,Mode=TwoWay,Converter={StaticResource EnumToBoolConverter},ConverterParameter=EnumValueName3}">
</RadioButton>
I am trying to bind directly to the data field called propertyName in my data structure defining the table that holds these values. I do NOT have this field in my ViewModel class for this view. I did this to avoid keeping track of the index of the collection that I am currently populating. (or so i'd like to think!)
The converter:
public class EnumBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string parameterString = parameter as string;
if (parameterString == null)
return DependencyProperty.UnsetValue;
if (value == null || Enum.IsDefined(value.GetType(), value) == false)
return DependencyProperty.UnsetValue;
object parameterValue = Enum.Parse(value.GetType(), parameterString);
return parameterValue.Equals(value);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string parameterString = parameter as string;
if (parameterString == null || value.Equals(false))
return DependencyProperty.UnsetValue;
return Enum.Parse(targetType, parameterString);
}
}
The problem is that in the ConvertBack function at the Enum.Parse line, the following Argument exception occurs:
Type provided must be an Enum.
Parameter name: enumType
Is there a way to return an enum type to the binding? How do I tell the radio buttons which enumeration value it represents? How do I write a function that returns the appropriate enum value to the binding?
Hoping you guys can help. Thanks in advance!
Try this, it's my version of the EnumToBoolConverter:
public class EnumToBoolConverter : BaseConverterMarkupExtension<object, bool>
{
public override bool Convert(object value, Type targetType, object parameter)
{
if (value == null)
return false;
return value.Equals(Enum.Parse(value.GetType(), (string)parameter, true));
}
public override object ConvertBack(bool value, Type targetType, object parameter)
{
return value.Equals(false) ? DependencyProperty.UnsetValue : parameter;
}
}
Ok the solution was relatively simple once I got the concept right. I have done the following which partially solves my problem.
<RadioButton Content="EnumValueName1"
GroupName="RadBtnGrp1"
IsChecked="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ParentControl}},
Path=DataContext.propName,
Mode=TwoWay,
Converter={StaticResource EnumToBoolConverter},ConverterParameter=EnumValueName1}">
</RadioButton>
The targetType in my ConvertBack function now the correct enum type. Hope this helps!
Now i have to figure out how to make the radiobuttons retain selections in multiple rows of the listview. Presently they a selection in first row deselects the same group from the rest of the rows.
Thank you for your help so far. If anyone can point me to a solution for the new problem that would be really great!
Recommend you to create the radio buttons dynamically, ListBox can help us do that, without converters. The advantage of this method is below:
if someday your enum class changes, you do not need to update the GUI (XAML file).
The steps of this method are below:
create a ListBox and set the ItemsSource for the listbox as the enum and binding the SelectedItem of the ListBox to the selected property.
Then the Radio Buttons for each ListBoxItem will be created.
Step 1: Re-define your Enum.
public enum EnumValueNames
{
EnumValueName1,
EnumValueName2,
EnumValueName3
}
Then add below property to your DataContext (or ViewModel of MVVM), which records the selected item which is checked.
public EnumValueNames SelectedEnumValueName { get; set; }
Step 2: add the enum to static resources for your Window, UserControl or Grid etc.
<Window.Resources>
<ObjectDataProvider MethodName="GetValues"
ObjectType="{x:Type system:Enum}"
x:Key="EnumValueNames">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:EnumValueNames" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Window.Resources>
Step 3: Use the List Box and Control Template to populate each item inside as Radio button
<ListBox ItemsSource="{Binding Source={StaticResource EnumValueNames}}" SelectedItem="{Binding SelectedEnumValueName, Mode=TwoWay}" >
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<RadioButton
Content="{TemplateBinding ContentPresenter.Content}"
IsChecked="{Binding Path=IsSelected,
RelativeSource={RelativeSource TemplatedParent},
Mode=TwoWay}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
</ListBox>
References:
https://www.codeproject.com/Articles/130137/Binding-TextBlock-ListBox-RadioButtons-to-Enums