Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wpf DataGrid SelectedItem loses binding after cell edit

I have a DataGrid bound to a collection of items (Rules). If I edit one of these items manually in the DataGrid, it seems like the SelectedItem binding on the grid stops working (RuleListViewModelPropertyChanged in the controller is never called again). But only if I actually change the value of the item in the cell, otherwise SelectedItem keeps working like it should.

I have stripped the code of some irrelevant things, so this is basically what I have. First, I have the following DataGrid:

<DataGrid x:Name="RuleTable" Grid.Row="1" Grid.ColumnSpan="2" ItemsSource="{Binding Rules}" SelectedItem="{Binding SelectedRule, Mode=TwoWay}" 
               BorderThickness="0" >
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding TargetValue, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, 
                                  ValidatesOnExceptions=True, NotifyOnValidationError=True}" 
                                Header="{x:Static p:Resources.TargetValue}" Width="*" ElementStyle="{StaticResource TextCellElementStyle}"
                                EditingElementStyle="{StaticResource TextCellEditingStyle}"/>
        </DataGrid.Columns>
    </DataGrid>

With a ViewModel that looks like this:

public class RuleListViewModel : ViewModel<IRuleListView>
{
    private IEnumerable<Rule> rules;
    private Rule selectedRule;

    public RuleListViewModel(IRuleListView view)
        : base(view)
    {
    }

    public RuleListViewModel() : base(null) {}

    public IEnumerable<Rule> Rules
    {
        get
        {
            return rules;
        }
        set
        {
            if (rules != value)
            {
                rules = value;
                RaisePropertyChanged("Rules");
            }
        }
    }

    public Rule SelectedRule
    {
        get
        {
            return selectedRule;
        }
        set
        {
            if (selectedRule != value)
            {
                selectedRule = value;
                RaisePropertyChanged("SelectedRule");
            }
        }
    }
}

And finally a Controller that looks like this:

public class RuleController : Controller
{
    private readonly IShellService shellService;
    private readonly RuleListViewModel ruleListViewModel;

    private readonly DelegateCommand addRuleCommand;
    private readonly DelegateCommand deleteRuleCommand;

    [ImportingConstructor]
    public RuleController(IShellService shellService, IEntityService entityService, RuleListViewModel ruleListViewModel)
    {
        this.shellService = shellService;
        this.ruleListViewModel = ruleListViewModel;
    }

    public void Initialize()
    {
        AddWeakEventListener(ruleListViewModel, RuleListViewModelPropertyChanged);
        shellService.RuleListView = ruleListViewModel.View;

        List<Rule> rules = GetRules();
        ruleListViewModel.Rules = new ObservableCollection<Rule>(rules);
    }

    private void RuleListViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "SelectedRule")
        {
            // This never gets called after edit
        }
    }
}

I have really no idea what the problem is, but since I actually have to change the value to experience this behavior (only clicking in the cell and not editing anything works fine) I'm guessing it has something to do with the SelectedItem binding breaking when I change the value of the item bound to it?!

like image 227
Joel Avatar asked Jan 10 '13 15:01

Joel


1 Answers

For anyone who comes across this thread and you are using ObservableCollection - check to see if you override GetHashCode() (I was doing equality testing via IEquatable). The bindings to SelectedItem and SelectedIndex break as soon as you make a change to a cell.

From MSDN (https://msdn.microsoft.com/en-us/library/system.object.gethashcode(v=vs.110).aspx):

"You can ensure that the hash code of a mutable object does not change while the object is contained in a collection that relies on its hash code."

And of course I was getting a hash on the editable (i.e. mutable) field...

like image 129
camster Avatar answered Sep 22 '22 14:09

camster