简体   繁体   中英

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

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.

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

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

That did the trick.

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

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; }

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}"

Yet another way for this error to crop up (erroneously in my opinion). I have a DataGrid where the ItemsSource row object contains a class object X. I display in individual columns from X.

The binding path looks like Binding="{Binding MyClassInstance.PropA}"

Also, the grid is set to allow the user to add rows. What I forgot to do on a row add was arrange for MyClassInstance to be initialized, therefore it was null. And when I removed focus from the new row, I would get the Two-way binding requires Path or XPath exception.

I found the real cause when in my attempts to fix one of the methods caused me to get the null value exception.

The stack trace for the binding needs a path error was quite extensive, which tells me that the developer once they got to the deep into the calls, guessed that the most likely reason for the null value was the path problem. Personally, for me it would have been more useful for the message of the exception to say "null value encountered, check that a path or xpath was specified."

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