How do I fix “Two-way binding requires Path or XPa

2019-02-12 03:58发布

问题:

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.

回答1:

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

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

That did the trick.



回答2:

A "Two-way binding requires Path or XPath" fault can be cause by a little difference in the name of the path in the XAML vs the one in the c# Binding element. The capitals letter are really important! That was my problem.

XAML:

<DataGridTextColumn Binding="{Binding Path=TotalHeure}"   ClipboardContentBinding="{x:Null}" Header="Total Heures" Width="80"/>

C#:

public string Totalheure { get; set; }

this will cause a Two-way binding requiring a Path or XPath error because they are not exactly the same and the programs is not able to find the binding path!

Maybe it will help someone else who made the Same mistake



回答3:

Ok, well, having typed all that in, I tried something which worked. I am posting anyway, in case it helps others.

The solution was to add to the problem member variables that are bound:

{ get; set; }

As in:

    public System.Nullable<decimal> Protein { get; set; }
    public System.Nullable<decimal> Carb { get; set; }
    public System.Nullable<decimal> Fat { get; set; }
    public System.Nullable<decimal> ProteinPercent { get; set; }
    public System.Nullable<decimal> CarbPercent { get; set; }
    public System.Nullable<decimal> FatPercent { get; set; }
    public System.Nullable<int> NonPFWMeals { get; set; }
    public System.Nullable<bool> Skip { get; set; }


回答4:

One can sometimes do a weird little thing when you get tired at the end of the day. I have a Datagrid binding to an entity Framework Entity called Dependant - fields Name_of_Dependant / Relationship / Date_of_Birth. Somehow I decied to create new properties : FullNames / Relationship / DateOfBirth - all the right types.
So in my datagrid I bind to an

ObservableCollection<Dependant> 

But my columns should then bind to the columns in my entity table Dependant. So this is correct:

Binding="{Binding Name_of_Dependant}"

This was wrong:

Binding="{Binding FullNames}"