1

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.

3
  • Top tip: if you're using C#6 or above, you can use PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); instead of creating a variable and checking for null :) Commented May 20, 2017 at 21:01
  • First rename the dataTable to DataTable no the issue just annoying. Second for the name of the property use "DataTable" not "Grid" or use a proper implementation for notification. You can also use the nameof(DataGrid) in c# 6 Commented May 20, 2017 at 21:05
  • Implemented both of these suggestions; Still haven't gotten it to work, but with the changes I've made here I'm hoping that prior articles might get me up and going. Commented May 20, 2017 at 23:26

2 Answers 2

2

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) - e.g.: 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 :)

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the response. I changed the name to "dataTable" and it is still not working. I'm also going to refactor based on your feedback. I have concerns that my binding in the XAML headers is not correct, could that be why its not pulling in the correct information?
2

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.