简体   繁体   中英

WPF datagrid binding issue: first row bound but doesn't update selected item in two-way fashion

The Setup

  • I have a DataGrid that holds a list of custom types ("Previous Documents") and binds to them. That part works correctly.
  • I have bound the SelectedItemProperty of the datagrid to a property on my ViewModel called CurrentlySelectedPreviousDocument
  • I have the left-click action of the datagrid bound to a command called OpenPreviousDocumentCommand
  • The OpenPreviousDocumentCommand runs a method called OpenSelectedPreviousDocument()
  • OpenSelectedPreviousDocument() uses the CurrentlySelectedPreviousDocument property to copy a file to the temporary directory and open it.

The Problem

  • This code works, but only if you click on the first item in the datagrid.
  • For every other item in the datagrid, it appears that CurrentlySelectedPreviousDocument is shown as null, so all of the properties are null.

More scenarios to help describe the problem:

  • When I load the application, no rows are selected.
  • If I double-click the first item at any point, it opens, even after clicking other items and seeing errors.
  • If I double-click the second or third items first, I receive the error.
  • If I double-click the first document to open it, then single-click another row to ensure it is selected, and then double-click on the other row, I still receive the error.
  • If I double-click the first document to open it, then click one of the faulty rows and receive an error, and then click on the first row again, it still works.

Things I've Tried So Far:

  • Updating the bingding mode to TwoWay
  • Adding an UpdateSourceTrigger = PropertyChanged
  • Checked the output window; no invalid bindings detected.

The Code

XAML DataGrid bindings:

<DataGrid 
    x:Name="PreviousDocumentsDataGrid"
    ItemsSource="{Binding PreviousDocumentsList}" 
    SelectedItem="{Binding CurrentlySelectedPreviousDocument, Mode=OneWayToSource}" 
    SelectionMode="Single"
    SelectionUnit="FullRow" 
    AutoGenerateColumns="False" 
    IsReadOnly="True" 
    HorizontalGridLinesBrush="LightGray" 
    VerticalGridLinesBrush="LightGray" 
    BorderBrush="Transparent" 
    Visibility="{Binding PreviousDocumentsFound, Converter={StaticResource BoolToVisConverter}}">
    <DataGrid.InputBindings>
        <MouseBinding Gesture="LeftDoubleClick" Command="{Binding OpenPreviousDocumentCommand}"/> 
    </DataGrid.InputBindings>
    <DataGrid.Columns>
        <DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
        <DataGridTextColumn Header="Reference Type" Binding="{Binding ReferenceType}"/>
        <DataGridTextColumn Header="Category ID" Binding="{Binding Category}"/>
        <DataGridTextColumn Header="Description" Binding="{Binding Description}"/>
        <DataGridTextColumn Header="Document Timestamp" Binding="{Binding Timestamp}"/>
    </DataGrid.Columns>
</DataGrid>

The ViewModel definition of CurrentlySelectedPreviousDocument:

public VEDocument CurrentlySelectedPreviousDocument
{
    get { return _currentlySelectedPreviousDocument; }
    set { _currentlySelectedPreviousDocument = value;
    OnPropertyChanged("CurrentlySelectedPreviousDocument");} //TODO: Is the on propertychanged actually necessary here?
}

Command Definition:

public ICommand OpenPreviousDocumentCommand
{
    get
    {
        return _openPreviousDocumentCommand ??
               (new CommandHandler(OpenSelectedPreviousDocument, _canExecuteCommands));
    }
}

Method in the ViewModel to open the document (uses the viewmodel property)

public void OpenSelectedPreviousDocument()
{
    var docToOpen = CurrentlySelectedPreviousDocument;
    ...etc. etc.
}

A lesson in debugging and posting questions -- this one is entirely on me.

What I did not mention , but should have, is that in offline mode I was using a fake service to return the list of documents.

If I'd mentioned that, I could have pasted the code and folks could have seen that my fake service wasn't returning a location for two of the documents (hence my issue).

I created a piece of debugging code that outputted the locations from the list itself when my viewmodel was opened. Doing this helped me see that it was the list that had the problem, not the binding. My assumption that I got the binding wrong (due to my inexperience with WPF) was actually a false one.

Big Thanks to sexta13 and meilke for helping me rule out other potential issues.

Lessons Learned / Reinforced:

  • When debugging, start at the source. Challenge your assumptions at each step of the process until
  • When using a fake anything, standardize the method for it returning values so that they will all be in the same format. I normally do that but didn't this once as a shortcut, and it bit me.
  • Mention and post the code that the situation touches, even if it seems unrelated . Had I posted the fakes and their code, someone likely would have helped me see the issue very quickly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM