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:
[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)
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) 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.