0
votes

This one is driving me crazy...

Here is the xaml I am using to bind a combobox that is in a column in a datagrid. The ItemSource is to an ObservableCollection holding the class "Pipetter". The CellTemplate, just needs to display the "name" property of this Pipetter class for the currently selected row.

The problem is, as soon as I choose a value in the combobox, the value that is chosen, suddenly appears in all of the rows for that column. I've reworked this many different ways, and it happened in each case. Any ideas on what setting is off?

<DataGridTemplateColumn.CellEditingTemplate>
    <DataTemplate>
        <ComboBox 
            IsEditable="False"  
            ItemsSource="{Binding DataContext.Pipettors, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Mode=TwoWay}"
            SelectedItem="{Binding DataContext.SelectedPipettor, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
            SelectedValue="{Binding TipGroup.PipettorTipType.Pipettor}"
            DisplayMemberPath="Name"
            />
    </DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>

<DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
        <Label 
            Content="{Binding TipGroup.PipettorTipType.Pipettor.Name}" 
            Style="{DynamicResource DataGridRowLabel}" 
            />
    </DataTemplate>
</DataGridTemplateColumn.CellTemplate>

Here is the property in the Vm that the selectedItem is bound to. I am just taking the "SelectedItem" and assigning it to the corresponding property in the currently selected row (SelectedTipGroup). This is defined as the "SelectedItem" in the DataGrid definition.

 private Pipettor selectedPipettor;
    public Pipettor SelectedPipettor
    {

        get { return selectedPipettor; }
        set
        {
            SetProperty(ref selectedPipettor, value);
            SelectedTipGroup.TipGroup.PipettorTipType.Pipettor = value;
        }
    }

I Updated the combobox binding as suggested:

<DataGridTemplateColumn.CellEditingTemplate>
      <DataTemplate>
          <ComboBox x:Name="PipetterComboBox"
              ItemsSource= "{Binding DataContext.Pipettors, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Mode=TwoWay}"
                                  SelectedItem="{Binding TipGroup.PipettorTipType.Pipettor}" IsSynchronizedWithCurrentItem="True"
                                  DisplayMemberPath="Name"
                                 />
                    </DataTemplate>
                </DataGridTemplateColumn.CellEditingTemplate>

                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Label Content="{Binding TipGroup.PipettorTipType.Pipettor.Name}" Style="{DynamicResource DataGridRowLabel}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>

And still when a selection is made in one row of the datagrid, the same value appears in all rows for that column... It's just trying to assign the selectedItem class to the class property "Pipettor" in the current row...

Have spent DAYS on this one.. makes no sense...

Thanks!

This is the property that the combobox is binding to..The ItemsSource for the combobox is just an observablecollection of type Pipettor.

  private Pipettor pipettor;
    [DataMember]
    public Pipettor Pipettor
    {
        get { return this.pipettor; }
        set
        {
            if (SetProperty(ref this.pipettor, value))
            {
                //***BKM This was failing on delete - not sure if masking or not but will null check
                //note something similar in other models - review
                if (value != null)
                {
                    this.pipettorId = this.pipettor.Identity;

                }
            }
        }
    }

And SetProperty()

 protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (object.Equals(field, value)) 
        { 
            return false; 
        }

        field = value;
        //Check to make sure Tracking is Initialized but no need to do anything
        if (!this.Tracking.Initialized)
        {

        }

        RaisePropertyChanged(propertyName);
        return true;
    }
1
maybe notify IPropertyChanged in your setter of the property?ProgrammingDude
What does SetProperty do? Is PropertyChanged fired in there by any chance?15ee8f99-57ff-4f92-890c-b56153
setproperty just encapsulates the check to see if the new value is != current value and if it is it raises the propertyChanged event and sets the backing field to the new value.Harold Chattaway

1 Answers

0
votes

The SelectedItem for your ComboBox is using a RelativeSource to use the DataContext of the DataGrid, so all the rows are using the same SelectedItem. Change this to a binding in the item for each row in the DataGrid. It looks like you may already have this binding on the SelectedValue, which looks like it should really be on the SelectedItem.

The SelectedValue binding doesn't work as is because the SelectedValuePath is not set. See this question for the difference between SelectedItem and SelectedValue: Difference between SelectedItem, SelectedValue and SelectedValuePath

Edit: After the question was updated per this answer, IsSynchronizedWithCurrentItem="True" was added in the xaml for the ComboBox. From MSDN's documentation for this property:

"You can set the IsSynchronizedWithCurrentItem property to true to ensure that the item selected always corresponds to the CurrentItem property in the ItemCollection. For example, suppose that there are two ListBox controls with their ItemsSource property set to the same source. Set IsSynchronizedWithCurrentItem to true on both list boxes to ensure that the selected item in each ListBox is the same."

Setting this to true this also caused all the ComboBoxes to use the same selection. Remove this property from the xaml for the ComboBox.

MSDN reference: https://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.selector.issynchronizedwithcurrentitem(v=vs.110).aspx