2

EDIT (clarification of requirements)

I have a DataGrid as shown below. The values in the "Field Name To Store Old EmpNo" column change based on the value selected in "New EmpNo Rule" column. To accommodate this, each item in the DataGrid ItemsSource has its own TableNameForOldDataCollection. I need to bind to this TableNameForOldDataCollection and not a static property that cannot change.

If there is a way to do this binding while using DataGridComboBoxTemplate I would prefer that. If not, I would like to know if it is possible to template the DataGridTemplateColumn/ComboBox to match that of the DataGridComboBoxTemplate

OP

I have a scenario where I am using DataGridComboBoxColumn for one of the DataGrid columns. In another column, I need to use the DataGridTemplateColumn, with a ComboBox, to properly bind to a dynamic ItemSource in the VM.

The DataGridComboBoxColumn ("New EmpNo Rule") is styled differently than the DataGridTemplateColumn, with a ComboBox ("Field Name To Store Old EmpNo") as shown here:

enter image description here

How can I style the DataGridTemplateColumn/ComboBox to match the DataGridComboBoxColumn, particularly how the combobox is hidden when the actual cell is not selected (like the second row of "New EmpNo Rule").

EDIT (added DataGrid code):

   <UserControl.Resources>
        <ResourceDictionary>
             <CollectionViewSource x:Key="StaticEmpNoRuleCollection" Source="{Binding EmpNoRuleCollection}" />                
        </ResourceDictionary>        
    </UserControl.Resources>

....

                <DataGrid Name="DataGrid_MultiCompanyInfo"
                          ItemsSource="{Binding Model.EmpNoOptionsCollection}"
                          SelectedItem="{Binding SelectedEmpNoOptions}"
                          AutoGenerateColumns="False"
                          CanUserAddRows="False"
                          CanUserDeleteRows="False">
                    <DataGrid.Columns>

                        <!-- Company -->
                        <DataGridTextColumn Header="Company" 
                                            Binding="{Binding Company}"
                                            IsReadOnly="True" />

                        <!-- New EmpNo Rule -->
                        <DataGridComboBoxColumn Header="New EmpNo Rule"
                                                Width="200"
                                                ItemsSource="{Binding Source={StaticResource StaticEmpNoRuleCollection}}"
                                                DisplayMemberPath="Description"
                                                SelectedValueBinding="{Binding SelectedEmpNoRule, UpdateSourceTrigger=PropertyChanged}"/>

                        <!-- Field Name To Store Old EmpNo -->
                        <DataGridTemplateColumn Header="Field Name To&#x0a;Store Old EmpNo"
                                                Width="150" >
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <ComboBox Name="OldEmpNo_ComboBox"
                                              Margin="-5,0,0,0"
                                              ItemsSource="{Binding TableNameForOldDataCollection}"
                                              SelectedValue="{Binding TableNameForOldData, UpdateSourceTrigger=PropertyChanged}" />
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>

                        ...

                    </DataGrid.Columns>
                </DataGrid>
BrianKE
  • 4,035
  • 13
  • 65
  • 115
  • Could you please post your DataGridTemplateColumn Code? – Jose Sep 20 '16 at 13:44
  • @Kirenenko Please see edit to OP. – BrianKE Sep 20 '16 at 13:53
  • I think that the correct way to go is to use DataGridComboBoxColumn on "Old EmpNo" to, but you should correctly bind, using `RelativeSource="{RelativeSource AncestorType={x:Type DataGrid}}"`. – Jose Sep 20 '16 at 14:06
  • @Kirenenko I originally went this route which didn't work. According to a number of different articles I have found, you cannot do what you are suggesting because DataGridComboBoxColumn is not a part of the visual tree (http://stackoverflow.com/questions/3659970/datagridcomboboxcolumn-itemsource-binding-doesnt-work). This is why I have to use the DataGridTemplateColumn. This particular column's selectable values changes based on other columns selected value. – BrianKE Sep 20 '16 at 14:10
  • Possible duplicate of [How to Bind data to DataGridComboBoxColumn in DataGrid using MVVM](http://stackoverflow.com/questions/3563325/how-to-bind-data-to-datagridcomboboxcolumn-in-datagrid-using-mvvm) – Jose Sep 22 '16 at 09:46

1 Answers1

0

Keeping in mind that DataGridComboBoxColumn is not in the same visual tree, you can use a BindingProxy:

public class BindingProxy : Freezable
{
    #region Overrides of Freezable

    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }

    #endregion

    public object Data
    {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}

XAML resources:

<Window.Resources>
    <local:BindingProxy x:Key="proxy" Data="{Binding}" />
</Window.Resources>

XAML binding(not on the visual tree):

<DataGridComboBoxColumn ItemsSource="{Binding Data.TableNameForOldDataCollection, Source={StaticResource proxy}}"/>

UPDATE

Totally different solution...Looks a little hackish, but I've tested it an it works:

<DataGridComboBoxColumn Header="Field Name To&#x0a;Store Old EmpNo" Width="150"
SelectedItemBinding="{Binding TableNameForOldData, UpdateSourceTrigger=PropertyChanged}>
    <DataGridComboBoxColumn.ElementStyle>
        <Style TargetType="ComboBox">
            <Setter Property="ItemsSource" Value="{Binding TableNameForOldDataCollection}"/>
            <Setter Property="IsReadOnly" Value="True"/>
        </Style>
    </DataGridComboBoxColumn.ElementStyle>
    <DataGridComboBoxColumn.EditingElementStyle>
        <Style TargetType="ComboBox">
            <Setter Property="ItemsSource" Value="{Binding TableNameForOldDataCollection}"/>
        </Style>
    </DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>

Also I think it is a duplicate, so I will flag it.

Community
  • 1
  • 1
Jose
  • 1,857
  • 1
  • 16
  • 34
  • While I like this option of providing a bindable collection, it doesn't work for my scenario (see added requirements in OP). It appears to bind to a collection on the DataGrid itself and not a property in each of the items in EmpNoOptionsCollection. If I am missing something and this would work to fulfill the requirements can you please explain further? – BrianKE Sep 20 '16 at 17:59
  • I thought that your `TableNameForOldDataCollection` was on your main DataContext/ViewModel. Just tell me where is the object to bind, because you have to point the proxy "Data" to it. – Jose Sep 21 '16 at 06:43
  • The `TableNameForOldDataCollection` is on each individual item in `Model.EmpNoOptionsCollection`. Each item in the `DataGrid` has its own copy of `TableNameForOldDataCollection` because the values can change based on the value of `StaticEmpNoRuleCollection` – BrianKE Sep 21 '16 at 11:31
  • Woah...Now I understand...This is some kind of `ItemsourceBindIngCeption`. Let me check If I can do something, but not so sure... – Jose Sep 21 '16 at 12:28