简体   繁体   中英

Binding DataTable to DataGrid C# WPF MVVM

New to MVVM and struggling to figure out where I went wrong when attempting to bind a dynamically generated DataTable with a DataGrid. I've found some solutions and attempted to make adjustments to my implementation based on previous responses:

XAML:

<DataGrid x:Name="Grid" Margin="5,0,0,0" ItemsSource="{Binding dataTable, Mode=TwoWay}" AutoGenerateColumns="False" VerticalAlignment="Center">
<DataGrid.Columns>
    <DataGridTextColumn Header="Header1" Binding="{Binding Column1Name}"/>
    <DataGridTextColumn Header="Header2" Binding="{Binding Column2Name}"/>
</DataGrid.Columns>
<DataGrid.DataContext>
    <ViewModels:Presenter/>
</DataGrid.DataContext>

XAML CS:

DataTable dataTable = new DataTable();
Grid.DataContext = dataTable.DefaultView;
//I don't believe I should be using System.Data in View?

ViewModel

.Presenter:

public class Presenter : ObservableObject {
private DataTable _dataTable;


public DataTable dataTable
    {
        get { return _dataTable; }
        set
        {
            _dataTable = value;
            RaisePropertyChangedEvent("Grid");
        }
    }

private void ParseData()
    {
        if (string.IsNullOrWhiteSpace(ID)) return;
        dataTable = DataParser.ParseURL(ID);
    }
}

.ObservableObject

public class ObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChangedEvent(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

I know the data from the model is returning correctly, and when I'm in debugger the RaisePropertyChangedEvent is firing, but the view is not being updated.

You're raising the wrong PropertyName (which appears to be the name of your Grid in the XAML.

Raise the name "dataTable" when calling your RaisePropertyChanged method.

Like so:

public DataTable dataTable
{
    get { return _dataTable; }
    set
    {
        _dataTable = value;
        RaisePropertyChangedEvent("dataTable");
    }
}

A few other things you can do are:

  • Use [CallerMemberName] attribute before the propertyName parameter. This will save you having to provide it, as it detects what property is calling it (C#5 and above) - eg: protected void RaisePropertyChangedEvent([CallerMemberName] string propertyName)
  • Use PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); in your RaisePropertyChanged method. This saves you having to create a variable and check for null (C#6 and above)
  • Rename your dataTable property to DataTable - it creates better clarity as to what are properties and what are fields, and it's a commonplace thing to do in C#

Hope this helps :)

Since you are setting the DataContext of the DataGrid to the DataView of the DataTable like this:

Grid.DataContext = dataTable.DefaultView;

...you should bind directly to the DataContext :

<DataGrid x:Name="Grid" Margin="5,0,0,0" ItemsSource="{Binding}" AutoGenerateColumns="False" VerticalAlignment="Center">
...

If you want to bind to your dataTable property, you should set the DataContext to an instance of your Presenter class:

var p = new Presenter();
Grid.DataContext = p;

<DataGrid x:Name="Grid" Margin="5,0,0,0" ItemsSource="{Binding dataTable}" AutoGenerateColumns="False" VerticalAlignment="Center">

Then you can set the dataTable property of the Presenter object to a new DataTable :

p.dataTable = new DataTable();

You still need to modify your property as suggested by @Geoff James:

public DataTable dataTable
{
    get { return _dataTable; }
    set
    {
        _dataTable = value;
        RaisePropertyChangedEvent("dataTable");
    }
}

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