How do I fix "Two-way binding requires Path or XPath" exception in WPF Datagrids?

Dronz picture Dronz · Feb 26, 2012 · Viewed 29.7k times · Source

Background/context for this question: I have a WPF desktop application. It uses LINQ to SQL to connect to its SQL database, and it displays its data in WPF Datagrids. It was working fairly well, but performance was a problem because LINQ can be deadly slow, so I have been switching my logic and UI controls away from LINQ database contexts as much as possible, and instead loading them into local variables which are very similar to the LINQ objects, which massively improves performance.

The problem: As I test my Datagrids, I am now getting a new exception "Two-way binding requires Path or XPath." when I try to edit the value in a certain (integer) column of one Datagrid, though editing string columns had been working fine. I don't understand why I am getting this, or what to do about it.

So it worked when the datagrid.datacontext was set to a LINQ entity association, but it only almost works when it is set to a list of plain objects. I tried changing the list to an ObservableCollection, but this had no apparent effect.

I have looked at about a dozen different related questions here and on other sites, and am not seeing anything that seems to help.

Currently I have:

<DataGrid Margin="12,110,12,0" x:Name="dgDays" ItemsSource="{Binding}" 
                 Height="165" VerticalAlignment="Top" MinHeight="0" 
                 AutoGenerateColumns="False"
                 SelectionChanged="dgDays_SelectionChanged">

...

<DataGrid.Columns>
            <DataGridComboBoxColumn Width="80" Header="Cook" x:Name="_DailyCookCombo" SelectedItemBinding="{Binding sCook}"/>
            <DataGridComboBoxColumn Width="80" Header="Eat" x:Name="_DailyDayCombo" SelectedItemBinding="{Binding sDay}"/>
            <DataGridTextColumn Width="52" Header="Prot" Binding="{Binding Protein}" />
            <DataGridTextColumn Width="52" Header="Carb" Binding="{Binding Carb}" />
            <DataGridTextColumn Width="52" Header="Fat" Binding="{Binding Fat}" />
            <DataGridTextColumn Width="62" Header="Prot %" Binding="{Binding ProteinPercent}" />
            <DataGridTextColumn Width="62" Header="Carb %" Binding="{Binding CarbPercent}" />
            <DataGridTextColumn Width="62" Header="Fat %" Binding="{Binding FatPercent}" />
            <DataGridTextColumn Width="116" Header="non PFW meals" Binding="{Binding NonPFWMeals}" />
            <DataGridTextColumn Width="55" Header="Prot" Binding="{Binding CalcProt}" IsReadOnly="True" />
            <DataGridTextColumn Width="55" Header="Carb" Binding="{Binding CalcCarbs}" IsReadOnly="True" />
            <DataGridTextColumn Width="55" Header="Fat" Binding="{Binding CalcFat}" IsReadOnly="True" />
            <DataGridTextColumn Width="65" Header="KCal" Binding="{Binding CalcKCal}" IsReadOnly="True" />
            <DataGridCheckBoxColumn Width="32" Header="Skip" Binding="{Binding Skip}"  />
            <DataGridTextColumn Width="70" Header="Date" Binding="{Binding sNextDate}" IsReadOnly="True" />
        </DataGrid.Columns>
    </DataGrid>

which is bound by the code:

dgDays.DataContext = TheMember.RAM_Member_Requirements_Days;

which is defined as:

public ObservableCollection<RAM_Member_Requirements_Day> RAM_Member_Requirements_Days = new ObservableCollection<RAM_Member_Requirements_Day>();

whose bound members are:

    public class RAM_Member_Requirements_Day : INotifyPropertyChanged
{
    // RAM equivalents of DB values:
public System.Nullable<decimal> Protein;
public System.Nullable<decimal> Carb;
public System.Nullable<decimal> Fat;
public System.Nullable<decimal> ProteinPercent;
public System.Nullable<decimal> CarbPercent;
public System.Nullable<decimal> FatPercent;
public System.Nullable<int> NonPFWMeals;
public System.Nullable<bool> Skip;
public System.Nullable<System.DateTime> SkipDate;

I found a very simple fix shortly after typing this, which I'll post when the site lets me after its 8-hour delay.

Answer

Lynn Crumbling picture Lynn Crumbling · Apr 27, 2017

I ran into this problem with a bound textbox. My solution was to explicitly bind to ".":

<TextBox Text="{Binding Path=.}" />

That did the trick.