2

For now, I have something like that (2 columns with dropboxes containing values independent from each other):

<xcdg:DataGridControl.Columns>
    <xcdg:Column Title="A"
                 FieldName="A"
                 CellContentTemplate="{StaticResource ADT}"
                                         GroupValueTemplate="{StaticResource ADT}"
                                         Converter="{StaticResource AConverter}"
                 CellEditor="{StaticResource AEditor}"/>
    <xcdg:Column Title="B"
                 FieldName="B"
                 CellContentTemplate="{StaticResource BDT}"
                                         GroupValueTemplate="{StaticResource BDT}"
                                         Converter="{StaticResource BConverter}"
                 CellEditor="{StaticResource BEditor}"/>
</xcdg:DataGridControl.Columns>

And I would like the B column to be a dropbox containing values depending on the value selected in the first column.

I don't know how to achieve that. I read about Binding.RelativeSource but I think it is not at all what I should use.

Thanks

viggity
  • 15,039
  • 7
  • 88
  • 96
azerty
  • 698
  • 7
  • 28

1 Answers1

2

I can think of two ways to do that, and since you didn't provide your exact case, i will provide a simple scenario and build my answer base on it,

let say you have a DataGrid with two editable columns (A and B), in the edit mode you can choose the A value from a combobox list, and then the B combobox will be filtered to show only the items whom their value starts with the A value for example, if A="aa", B should be {"aaaa","aabb"}, to implement that you need first a Model that represent the DataGrid Items

 public class GridItem
    {
        public String A { get; set; }
        public String B { get; set; }
    }

In your codebehind / ViewModel define those properties (the DataGrid , and the comboboxes ItemSource Collections) :

private ObservableCollection<GridItem> _gridItemsCollection = new ObservableCollection<GridItem>()
    {
        new GridItem()
        {
            A="aa",
            B="bbbb"
        }
    };
public ObservableCollection<GridItem> GridItemsCollection
    {
        get
        {
            return _gridItemsCollection;
        }

        set
        {
            if (_gridItemsCollection == value)
            {
                return;
            }

            _gridItemsCollection = value;
            OnPropertyChanged();
        }
    }
         //for the first Combobox
private ObservableCollection<String> _aCollection = new ObservableCollection<String>()
    {
        "aa",            
        "bb"           
    };
public ObservableCollection<String> ACollection
    {
        get
        {
            return _aCollection;
        }

        set
        {
            if (_aCollection == value)
            {
                return;
            }

            _aCollection = value;
            OnPropertyChanged();
        }
    }
    //for the second Combobox
private ObservableCollection<String> _bCollection ;
public ObservableCollection<String> BCollection
    {
        get
        {
            return _bCollection;
        }

        set
        {
            if (_bCollection == value)
            {
                return;
            }

            _bCollection = value;
            OnPropertyChanged();
        }
    }

Define a full B collection from which your B combobox's itemsource will be populated

ObservableCollection<String> MainBCollection = new ObservableCollection<String>()
    {
        "aaaa",            
        "aabb",            
        "bbaa",            
        "bbbb"           
    };

Finally the population of the B combobox will be based on the selected item in the A combobox using this property,

private String _selectedAItem;
    public String SelectedAItem
    {
        get
        {
            return _selectedAItem;
        }

        set
        {
            if (_selectedAItem == value)
            {
                return;
            }

            _selectedAItem = value;
            OnPropertyChanged();
            var returnedCollection = new ObservableCollection<String>();
            foreach (var val in MainBCollection)
            {
                if (val.StartsWith(_selectedAItem))
                {
                    returnedCollection.Add(value);
                }
            }
            BCollection = new ObservableCollection<string>(returnedCollection);

        }
    }

You need of course to implement the INotifypropertyChanged Interface, so that the B Combobox Itemsource will be updated,

Now regarding the Xaml, due to some limitations in Xceed you need to specify the Combobox's ItemSource and SelectedItem using the RelativeSource and Ancestor binding,

<Grid >           
    <xcdg:DataGridControl ItemsSource="{Binding GridItemsCollection}" AutoCreateColumns="False" SelectionMode="Single" >
        <xcdg:DataGridControl.Columns>
            <xcdg:Column Title="A"
                     FieldName="A"                        
                     >
                <xcdg:Column.CellContentTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding}"/>
                    </DataTemplate>
                </xcdg:Column.CellContentTemplate>
                <xcdg:Column.CellEditor>
                    <xcdg:CellEditor>
                        <xcdg:CellEditor.EditTemplate>
                            <DataTemplate>
                                <ComboBox Name="AComboBox" SelectedItem="{Binding SelectedAItem, RelativeSource={RelativeSource FindAncestor, 
                                                        AncestorType={x:Type Window}}}"   SelectedValue="{xcdg:CellEditorBinding}"
                          ItemsSource="{Binding RelativeSource=
                                                        {RelativeSource FindAncestor, 
                                                        AncestorType={x:Type wpfApplication3:MainWindow}}, 
                                                        Path=ACollection}">

                                </ComboBox>
                            </DataTemplate>
                        </xcdg:CellEditor.EditTemplate>
                    </xcdg:CellEditor>
                </xcdg:Column.CellEditor>
            </xcdg:Column>
            <xcdg:Column Title="B"
                     FieldName="B"
                     >
                <xcdg:Column.CellContentTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding}"/>
                    </DataTemplate>
                </xcdg:Column.CellContentTemplate>
                <xcdg:Column.CellEditor>
                    <xcdg:CellEditor>
                        <xcdg:CellEditor.EditTemplate>
                            <DataTemplate>
                                <ComboBox Name="AComboBox" SelectedValue="{xcdg:CellEditorBinding}"  ItemsSource="{Binding RelativeSource=
                                                        {RelativeSource FindAncestor, 
                                                        AncestorType={x:Type Window}}, 
                                                        Path=BCollection}">


                                </ComboBox>
                            </DataTemplate>
                        </xcdg:CellEditor.EditTemplate>
                    </xcdg:CellEditor>
                </xcdg:Column.CellEditor>
            </xcdg:Column>
        </xcdg:DataGridControl.Columns>
    </xcdg:DataGridControl>

</Grid>

and the result is something like that

first Second

The Other way to do that is by using a MultivalueConverter and update the B Collection eachtime the A SelectedValue is changed, something like that :

<xcdg:CellEditor.EditTemplate>
                            <DataTemplate>
                                <ComboBox Name="AComboBox" SelectedValue="{xcdg:CellEditorBinding}">
                                    <ComboBox.ItemsSource>
                                        <MultiBinding Converter="{StaticResource BCollectionConverter}">
                                            <Binding Path="BCollection" RelativeSource="{RelativeSource AncestorType={x:Type Window}}"/>
                                            <Binding Path="SelectedValue" ElementName="AComboBox" />
                                        </MultiBinding>                                                                                         
                                    </ComboBox.ItemsSource>
                                </ComboBox>
                            </DataTemplate>
                        </xcdg:CellEditor.EditTemplate>

And implement the converter to update the B Combobox's ItemSource,

public class BCollectionConverter:IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values == null)
            return null;
        var bCollection = (values[0] as ObservableCollection<String>);
        var aSelectedItem = (values[1] as String);

        if (aSelectedItem == null)
            return null;
        var returnedCollection = new ObservableCollection<String>();
        foreach (var value in bCollection)
        {
            if (value.StartsWith(aSelectedItem))
            {
                returnedCollection.Add(value);
            }
        }
        return returnedCollection;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

I didn't try that last one, you might as well give it a try, I hope that did help.

SamTh3D3v
  • 9,854
  • 3
  • 31
  • 47
  • I did not have time to test any of the solutions yet but I will try your second option asap. Thanks – azerty Sep 02 '15 at 10:34
  • Where does the "wpfApplication3:MainWindow" come from ? – azerty Sep 21 '15 at 14:41
  • MyNameSpace:MyClassThat_Inherit_from_Window....change it to AncestorType={x:Type Window} it will works fine as well – SamTh3D3v Sep 21 '15 at 14:47
  • I try with the first option (not using the multibinding), and when I open the grid, I see the default value we entered (aa, bbbbb) in GridItemsCollection , but the comboboxes are empty. GridItemsCollection and Acollection are defined one after each other, so I don't understand why it find one and not the other. – azerty Sep 21 '15 at 15:46