How to solve generic ComboBox representation in a generic GridView - c#

I have a DataGrid in a user control (DataGridView). This usercontrol propagates a binding to DataGrid's ItemsSource from anywhere in the application and fills it with List of K.
For this example lets define clas for K that has some properties with custom attributes:
public class Foo
{
[Enumeration(IsEnum=true, EnumerationType=typeof(MessageType))] //MessageType is enumeration and is consisted of values: 'Error', 'Warning' and 'Info'
public MessageType MessageType { get; set; }
[Enumeration(IsEnum=true, EnumerationType=typeof(FooType))] //FooType is enumeration and is consisted of values: 'Sweet' and 'Salty'
public FooType FooType { get; set; }
}
DataGrid has an event for autogenerating columns.
private void OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
foreach (Attribute attribute in (e.PropertyDescriptor as System.ComponentModel.PropertyDescriptor).Attributes)
{
Utilities.EnumerationAttribute enumAttribute = attribute as Utilities.EnumerationAttribute;
if (enumAttribute != null
&& enumAttribute.IsEnum)
{
DataGridTemplateColumn templateColumn = new DataGridTemplateColumn();
templateColumn.CellTemplate = (DataTemplate)Resources["enumTemplate"];
e.Column = templateColumn;
}
}
e.Column.IsReadOnly = true;
}
Resource for "enumTemplate" is defined in MergedDictionary as DataTemplate
<DataTemplate x:Key="enumTemplate">
<StackPanel>
<ComboBox/>
</StackPanel>
</DataTemplate>
What I was intending to do is to set ItemsSource of each ComboBox the grid will generate with return value of Enum.GetNames(enumAttribute.EnumerationType) which is of type string[].
Now there is a lot of anonymity here and I don't know names of properties, their types or even the type of object this DataGrid would display during the run time.
I had several tries into this ... like defining a property DataSourcesList of type List> where NamedArray holds items to fill the combobox and a name of the property (from e.PropertyName) so that I know which of the NamedArray to use for combobox being generated ... something like:
DataSourcesList.Add(new DataSourceWithMappedName<System.Object>() { MappedName = e.PropertyName, SourceList = Enum.GetNames(enumAttribute.EnumerationType) });
And then altering DataTemplate:
<DataTemplate x:Key="enumTemplate">
<DataTemplate.Resources>
<converters:IListToItemsSource x:Key="ilistToItemsSource"/>
</DataTemplate.Resources>
<StackPanel>
<ComboBox ItemsSource="{Binding DataSourcesList, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:DataGridView}}, Converter={StaticResource ilistToItemsSource}, ConverterParameter={Binding somethingButAllInVaine}}"/>
</StackPanel>
</DataTemplate>
, but this can't be done since ConverterParameter is not a DependencyObject and can not be bound.
Maybe I should state that the same principle should be later used for binding collections and not just enums.
So please, can anyone help me with a solution to generic ComboBox representation in a generic GridView.
Tnx and happy coding.

Perhaps it would be easier to set the DataTemplate up in code. Start by defining the datatemplate and then setting the ComboBox ItemSource Binding Source to the List of String resulting from the Enum.GetNames().
Code Way
// Create template
DataTemplate newTemplate = new DataTemplate();
FrameworkElementFactory stackFactory = new FrameworkElementFactory(typeof(StackPanel));
FrameworkElementFactory comboFactory = new FrameworkElementFactory(typeof(ComboBox));
Binding newBinding = new Binding();
newBinding.Source = Enum.GetNames(typeof(enumAttribute.EnumerationType));
comboFactory.SetBinding(ComboBox.ItemsSourceProperty, newBinding);
stackFactory.AppendChild(comboFactory);
newTemplate.VisualTree = stackFactory;
// Set the template
templateColumn.CellTemplate = newTemplate;
XAML / Code Way*
<CollectionViewSource x:Key="EnumCollection"/>
<DataTemplate x:Key="enumTemplate">
<StackPanel>
<ComboBox ItemsSource="{Binding Source={StaticResource EnumCollection}}" />
</StackPanel>
</DataTemplate>
Code (Make sure you set the Collection Source):
CollectionViewSource enumCollection = (CollectionViewSource)this.FindResource("EnumCollection");
enumCollection.Source =Enum.GetNames(typeof(enumAttribute.EnumerationType));
Pure Xaml
<ObjectDataProvider x:Key="EnumCollection"
MethodName="GetValues"
ObjectType="{x:Type sys:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="YourEnum" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<DataTemplate x:Key="enumTemplate">
<StackPanel>
<ComboBox ItemsSource="{Binding Source={StaticResource EnumCollection}}" />
</StackPanel>
</DataTemplate>

Related

Set Content of an Element without a Name-Property

I'm using a ListBox in combination with a ObservableCollection. The content is set via a TemplateSelector (TextBlock or Label). The text has to be formatted (f.e. with Run-Tags in Code-behind), but i can't access the Items. Is there a solution to get the elements?
I've tried the usage of OfType<>, but this works only on Panels. I searched for an children-attribute but, there isn't one for ListBoxes. Setting the Name-Property via binding is not possible for UId and Name.
An IEnumerator for the LogicalChildren doesn't work and iterate over the whole content everytime a new element is added, is not so optimal. Here a minimal example.
<Window.Resources>
<DataTemplate x:Key="TextBlockTemplate">
<StackPanel>
<TextBlock />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="LabelTemplate">
<StackPanel>
<Label/>
</StackPanel>
</DataTemplate>
<local:myTemplateSelector x:Key="myTemplateSelector" x:Name="myTemplateSelector" TextBlockTemplate="{StaticResource TextBlockTemplate}" LabelTemplate="{StaticResource LabelTemplate}"/>
</Window.Resources>
<Grid Margin="0">
<ListBox Name="mylist" Grid.Row="3"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemsSource="{Binding _listEntries}"
ItemTemplateSelector="{StaticResource myTemplateSelector}"
>
</ListBox>
</Grid>
Greetings and thanks :)
The TextBlock has an Inlines property that returns the Inline elements that comprise the contents of the TextBlock.
The Label has a Content property that you, depending on how you are using it, may cast to a Panel.
There are no inline elements for a TextBox.
Now, I found a solution. I made the TextBlock and Label as User Control and set the Name-property. In the code-behind, I have access to the DataContext and the element can set itself.
<UserControl x:Class="Test.TextBlockControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TextBlockControl"
Loaded="UserControl_Loaded">
<Grid>
<StackPanel HorizontalAlignment="Stretch" Margin="0,0,0,0">
<TextBlock Name="textBlock"/>
</StackPanel>
</Grid>
In the Code behind i can now access the values and set:
public partial class TextBlockControl : UserControl
{
public List<string> name => DataContext as List<string>;
public TextBlockControl()
{
InitializeComponent();
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
foreach (var t in name)
{
var run = new Run(t.Text);
if (t.IsHighlighted)
{
run.Foreground = Brushes.Green;
}
else
{
run.Foreground = Brushes.Red;
}
textBlock.Inlines.Add(run);
}
}
}
}
In the MainWindow, the dataTemplate then references the UserControl (root is the namespace):
<root:PickControl />

Setting binding source properly in XAML

I'd like to have a list of TextBlocks with ComboBoxes next to each of them.
The data source of ComboBoxes should be the same for every ComboBox. Each TextBlock however should contain sequent element of List
Both data source for ComboBoxs and TextBlocks are in my "settings" object. So I set DataContext of the whole window to this settings object.
Here's my problem:
Data source of TextBlock is: List called Fields, which is inside of an object called "Header" of type "Line" (which is of course inside settings object, which is my datacontext).
So, graphically:
settings(type: Settings) - Header(type: CsvLine) - Fields(type: List of string)
Now ComboBox. Data source of every ComboBox should be a List called Tags
Graphically:
settings(type: Settings) - Tags(type: List of string)
I don't know how I should point to these locations, I tried a lot of options, but none of them work. I see just a blank window.
Here's my code:
<Grid>
<StackPanel Orientation="Horizontal">
<ItemsControl ItemsSource="{Binding Headers}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Fields}"/>
<ComboBox ItemsSource="{Binding DataContext.Tags,
RelativeSource={RelativeSource AncestorType=ItemsControl}}">
</ComboBox>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
I have no idea what I should actually pass as ItemsSource to ItemsControl, because I think it should be common source for both TextBoxes and ComboBoxes, but their only common source is settings object - but i already set it as my DataContext.
I have used RelativeSource in ComboBox, but I'm not really sure what it's used for (although I read an article about it on MSDN). I don't know why but it's really hard for me to understand binding - I'm struggling to get anything working.
//EDIT:
Here's my Settings class - which is the type of my settings object:
public class Settings
{
public CsvLine AllHeaders1
{
get
{
return _allHeaders1;
}
}
public CsvLine _allHeaders1 = new CsvLine()
{
Fields = new List<string>()
{
"Header1" , "Header2" , "Header3"
}
};
private List<String> _tags;
public List<String> Tags
{
get
{
return new List<string>() { "Tag1", "Tag2", "Tag3", "Tag4", "Tag5" };
}
set
{
_tags = value;
}
}
}
And here's my CsvLine class:
public class CsvLine
{
public List<string> Fields = new List<string>();
public int LineNumber;
}
So, I'm not 100% sure of what it is you want, but the following should get you started.
Firstly, you need to ensure you bind to public properties - not public members - so the CsvLine.Fields member needs to be changed to public List<string> Fields { get { return _fields; } set { _fields = value; } }. Also not that, if you want changes in the settings object to be reflected in the UI, you will need to implement INotifyPropertyChanged.
Anyway, with this in place and assigned to the DataContext of the grid, the following will display a vertical list of text blocks (showing "Header 1", "Header 2", "Header 3") each with a combo box to the right containing the values "Tag1", "Tag2" ... "Tag5".
<Grid x:Name="SourceGrid">
<ItemsControl ItemsSource="{Binding Path=AllHeaders1.Fields}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" />
<ComboBox ItemsSource="{Binding ElementName=SourceGrid, Path=DataContext.Tags}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
Hope it helps.

How to group child objects from one List in a TreeView?

How do I take a List and then in a TreeView group them by their Class? I read this, but it doesn't group the child objects, it just has the related properties in collections instead.
Warehouse
Type A
Subtype 1
Subtype 2
Type B
Type C
If I have List that have all those types in there how do I show the grouping in a TreeView?
Before, I was manually adding them in, one TreeViewItem at a time.
List<Warehouse> myWarehouse = new List<Warehouse>();
TreeViewItem WarehouseNode = new TreeViewItem() { Header = "Warehouse" };
TreeViewItem TypeANode = new TreeViewItem() { Header = "Type A" };
foreach(SubtypeA type in myWarehouse) {
TypeANode.Items.Add(new TreeViewItem() { Header = type.Name };
}
WarehouseNode.Items.Add(TypeANode);
etc. for Type B and Type C.
I was reading about HierarchicalDataTemplate and it looks like this is how I want to go, using an ItemTemplateSelector to change the DataTemplate.
So, I started working with HierarchicalDataTemplates and came up with the below.
XAML:
<Window.Resources>
<Utility:MyTemplateSelector x:Key="MyTemplateSelector" />
<HierarchicalDataTemplate x:Key="TypeCTemplate" DataType="{x:Type EntityType:TypeC}"
ItemsSource="{Binding OBJS}" ItemTemplateSelector="{StaticResource MyTemplateSelector}">
<TextBlock Text="Type C"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="TypeBTemplate" DataType="{x:Type EntityType:TypeB}"
ItemsSource="{Binding OBJS}" ItemTemplateSelector="{StaticResource MyTemplateSelector}">
<TextBlock Text="Type B"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="TypeATemplate" DataType="{x:Type EntityType:TypeA}"
ItemsSource="{Binding OBJS}" ItemTemplateSelector="{StaticResource MyTemplateSelector}">
<TextBlock Text="Type A"/>
</HierarchicalDataTemplate>
</Window.Resources>
<Grid>
<TreeView Name="MyTreeView" ItemsSource="{Binding OBJS}"
ItemTemplateSelector="{StaticResource MyTemplateSelector}">
</TreeView>
</Grid>
I wrote a DataTemplateSelector:
class MyTemplateSelector : DataTemplateSelector {
public override DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container) {
MethodInfo mi = container.GetType().GetMethod("FindResource") as MethodInfo;
if(mi != null) {
string strItem = item.ToString().Split('.').Last();
switch(item.ToString().Split('.').Last()) {
case "Type A":
return mi.Invoke(container, new object[] { "TypeATemplate" }) as DataTemplate;
case "Type B":
return mi.Invoke(container, new object[] { "TypeBTemplate" }) as DataTemplate;
case "Type C":
return mi.Invoke(container, new object[] { "TypeCTemplate" }) as DataTemplate;
}
return null;
}
return null;
}
}
But now, when I look at the TreeView, it gives me this:
Type B
Type B
Type B
Type C
etc.
Group your collection by setting GroupDescriptions on its CollectionViewSource. You can do it in code by doing something like this:
CollectionViewSource.GetDefaultView(yourCollection).GroupDescriptions.Add(
new PropertyGroupDescription("PropertyName"));
Or you can do it in XAML by creating a CollectionViewSource explicitly.
<CollectionViewSource
Source="{StaticResource yourCollection}"
xmlns:dat="clr-namespace:System.Windows.Data;assembly=PresentationFramework">
<CollectionViewSource.GroupDescriptions>
<dat:PropertyGroupDescription PropertyName="PropertyName"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
Also check this out enter link description here

How to access textblock inside Datatemplate in combobox?

I am trying to Bind the TextBlock inside ComboBox through Code. I am able to bind the textblock sucessfully but For some reasons TextBlock doesnt display Text Values.
I have mechanism which checks for the selected values and there I am getting the selected values without any problem.
So to conclude, My binding is working fine but I am missing out something hence textblock is not displaying text that is bound with it.
This is the code I am using for Binding:
where "lObjTextBlock" is TextBlock inside of ComboBox.
TextBlock lObjTextBlock = (TextBlock)ComboBox.ItemTemplate.LoadContent();
Binding lObjBinding = new Binding();
lObjBinding.Path = new PropertyPath("[" + lObjMap.PropertyName + "]");
lObjTextBlock.SetBinding(TextBlock.TextProperty, lObjBinding);
This is the XAML for the TextBlock:
<my:HComboBox Name="cmbRefDoctor">
<my:HComboBox.ItemTemplate>
<DataTemplate>
<TextBlock x:Name="txtRefDoctorName" />
</DataTemplate>
</my:HComboBox.ItemTemplate>
</my:HComboBox>
Once again : My problem is that TextBlock is not displaying any Text althought values are being set.
Would love to get all possible suggestions. Thanks in advance.
it's one of the way to bind controls which inside datatemplate
this.DataContext = Person;
Binding binding = new Binding();
binding.Source = ob;
DataTemplate dtemp = (DataTemplate)Resources["PointTemp"];
Border bdr = dtemp.LoadContent() as Border;
TextBlock tblk = bdr.Child as TextBlock;
tblk.SetBinding(TextBlock.TextProperty, binding);
Here I used ob as double collection assign to textproperty by binding source
<UserControl.Resources>
<DataTemplate x:Key="PointTemp">
<Border Margin="0,23,0,0" Background="Transparent">
<TextBlock Text="{Binding}" Foreground="White" FontSize="28" HorizontalAlignment="Center" VerticalAlignment="Center" TextAlignment="Center"/>
</Border>
</DataTemplate>
</UserControl.Resources>
And you can assign,
if it's combobox or listbox
Here Person is a class name, or set the class name in combobox itemsource

WPF DataGrid: DataGridComboxBox ItemsSource Binding to a Collection of Collections

Situation:
I've created a DataGrid in XAML and the ItemsSource is binded to an ObservableCollection of a certain class that contains properties. Then in C#, I create a DataGridTextColumn and a DataGridComboBoxColumn and binded these to the properties of the objects inside the ObservableCollection. I can bind the DataGridComboBoxColumn to a simple Collection but what I want to do is bind it to a collection of collections of strings so that for each row the ComboBox inside the DataGrid has a different collection of string. I have failed to do so...
Question:
How can I bind the DataGridCombBoxColumn so that I can have a different collection of strings for each row of this type of column?
Code Sample:
XAML:
<Window>
<!-- ... -->
WPFToolkit:DataGrid
x:Name="DG_Operations"
Margin="10,5,10,5"
Height="100"
HorizontalAlignment="Stretch"
FontWeight="Normal"
ItemsSource="{Binding Path=OperationsStats}"
AlternatingRowBackground="{DynamicResource SpecialColor}"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Visible"
SelectionMode="Extended"
CanUserAddRows="False"
CanUserDeleteRows="False"
CanUserResizeRows="True"
CanUserSortColumns="True"
AutoGenerateColumns="False"
IsReadOnly="False"
IsEnabled="True"
BorderThickness="1,1,1,1"
VerticalAlignment="Stretch"/>
<!-- ... -->
</Window>
C#:
public class DataModelStatsOperations
{
public ObservableCollection<IStatsOperation> OperationsStats { get; set; }
}
public interface IStatsOperation
{
string Operation { get; set; }
Collection<string> Data{ get; set; }
}
public class StatsOperation : IStatsOperation
{
public StatsOperation(string operation, Collection<string> data)
{
Operation = operation;
Data = data;
}
public string Operation { get; set; }
public Collection<string> Data{ get; set; }
}
private ObservableCollection<IStatsOperation> dataOperations_ =
new ObservableCollection<IStatsOperation>();
//...
Binding items = new Binding();
PropertyPath path = new PropertyPath("Operation");
items.Path = path;
DG_Operations.Columns.Add(new DataGridTextColumn()
{
Header = "Operations",
Width = 133,
Binding = items
});
DG_Operations.Columns.Add(new DataGridComboBoxColumn()
{
Header = "Data",
Width = 190,
ItemsSource = /*???*/,
SelectedValueBinding = new Binding("Data"),
TextBinding = new Binding("Data")
});
dataOperations_.Add(new StatsOperation(CB_Operation.SelectedItem.ToString(),
dataCollection));
DG_Operations.DataContext = new DataModelStatsOperations
{
OperationsStats = dataOperations_
};
//...
Any help would be greatly appreciated!
Notes:
Okay, so after reading the two first answers I noticed something. My binding is really not right! Now, what I want to do is something similar to what AndyG proposed:
DG_Operations.Columns.Add(new DataGridComboBoxColumn()
{
Header = "Data",
Width = 190,
ItemsSource = new Binding("Data"), //notice this here does not work (have a look at the following error)
SelectedValueBinding = new Binding("Operation"),
TextBinding = new Binding("Operation")
});
Error: "Cannot implicitly convert type 'System.Windows.Data.Binding' to 'System.Collections.IEnumerable'."
How can the ItemsSource be bound to Data?
Firstly, this should be easy... secondly, why are you building (and binding) columns in C#? Eek.
XAML (I'm using a regular grid because I'm lazy):
<ListView Name="MyListView">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn DisplayMemberBinding="{Binding Operation}" />
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Choices}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
C#:
void Window1_Loaded(object sender, RoutedEventArgs e)
{
var dahList = new List<StatsOperation>();
dahList.Add(new StatsOperation
{
Operation = "Op A",
Choices = new string[] { "One", "Two", "Three" },
});
dahList.Add(new StatsOperation
{
Operation = "Op B",
Choices = new string[] { "4", "5", "6" },
});
this.MyListView.ItemsSource = dahList;
}
The Results:
WPF grid with dynamic combo box choices http://www.singingeels.com/Articles/Articles/UserImage.aspx?ImageID=b1e3f880-c278-4d2b-bcc2-8ad390591200
I think the mistake is in how you've done your binding. When you define a column, the binding is related to the object that is represented by a particular row. So as I understand, you have a StatsOperation for each row, so the TextBox column is bound to operation, which is how you have it, and the ComboBox column ItemsSource should be bound to a Collection. Right now it looks like it's bound to a Collection<Collection<string>>.
I've not defined columns in code-behind before so here is an example in XAML. I've found ComboBoxColumn can be tricky sometimes so i've shown how you can have a combobox in the column by using either a TemplateColumn or a ComboBoxColumn. I've copy pasted from my own code so just replace 'dg' with 'WPFToolkit' in your case:
<dg:DataGrid
...
...>
<dg:DataGrid.Columns>
<dg:DataGridTextColumn Binding="{Binding Operation}" CanUserReorder="True" CanUserResize="True" Header="Operation" />
<dg:DataGridTemplateColumn CanUserReorder="True" CanUserResize="True" Header="Template Column">
<dg:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Data}" SelectedItem="{Binding Operation}" />
</DataTemplate>
</dg:DataGridTemplateColumn.CellTemplate>
</dg:DataGridTemplateColumn>
<dg:DataGridComboBoxColumn
Header="ComboBox Column"
SelectedValueBinding="{Binding Operation}"
SelectedItemBinding="{Binding Operation}">
<dg:DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="IsSynchronizedWithCurrentItem" Value="False" />
<Setter Property="ItemsSource" Value="{Binding Data}" />
</Style>
</dg:DataGridComboBoxColumn.ElementStyle>
<dg:DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding Data}" />
<Setter Property="IsDropDownOpen" Value="True" />
</Style>
</dg:DataGridComboBoxColumn.EditingElementStyle>
</dg:DataGridComboBoxColumn>
</dg:DataGrid.Columns>
</dg:DataGrid>
I'm assuming that Operation is the selected item, Data is the items to select from, and that your DataGrid is bound to a collection of StatsOperation. Good luck!
To fix your ItemsSource Binding Error use the form:
BindingOperations.SetBinding(new DataGridComboBoxColumn(), DataGridComboBoxColumn.ItemsSourceProperty, new Binding("Data"));
You obviously can't do this in the intializer so you'll have to move your declarations around a bit but that should take care of that error in your update.
EDIT I'm sorry, I'm little slow at midnights :). Here is an updated answer. It looks like great article from Vincent Sibal WPF DataGrid - DataGridComboBoxColumn v1 Intro answers your question. Does it?
Partial - I think there is a confusion in what you are saying. You said you need a collection of collection of strings in each row so that the combo box could show different strings for different rows. However, for a combo box to show a set of strings, you only need a collection of strings, per row, not a collection of collection of strings.
Now since you need the collection of strings per row you might be thinking that you would need collection of collection of strings.
Is my understanding of your question correct? If so, then your mention of collection of collection of strings is wrong.
What you actually need is collection of StatOperations in which each StatOperation should have a collection of strings. This is exactly how you had as shown in your classes above.
To make progress, I suggest you edit your question and point out where exactly you were stuck after fixing the binding as suggested by AndyG.
Let's bind the ItemsSource of your ComboBox to a property e.g. CurrentChoices of your viewmodel. This property should return a filtered list based on your current datagrid row selection. CompareWithSelectedRow is just a pseudo function to illustrate the example. Every time, when you click on ComboBox to populate choice list, this property will be call and return the right choice list. See example below, EntireChoiceList is a List of Tuple of string and List. There are room for improvments, e.g. using Dictionary or Lookup.
List<(string Key, List<string> Choices)> EntireChoiceList= new List<(string, List<string>)>();
public List<string> CurrentChoices
{
get => CurrentChoices.Where(q => CompareWithSelectedRow(q.Key, CurrentRow )).FirstOrDefault().Choices;
}
public object CurrentRow { get => ItemsView.CurrentItem; }
bool CompareWithSelectedRow(string key, object row)
{
return key == row; // here you should define compare expression
}
Use CollectionViewSource to get selected row in datagrid. Items is a list in view model which was bind to datagrid.
ItemsView = (CollectionView)CollectionViewSource.GetDefaultView(Items);
ItemsView.CurrentItem

Categories