Datagrid Binding in Wpf

DataGrid data binding and MVVM in WPF

step one: you created a window, its view model and connected them via DataContext. Already done

View.MainWindow mainWin = new View.MainWindow();
ViewModel.BookViewModel bookViewModel = new ViewModel.BookViewModel();
mainWin.DataContext = bookViewModel;

step two: fix (add) binding in xaml:

<DataGrid Name="BooksDataGrid" ItemsSource="{Binding Books}">
<DataGrid.Columns>
<DataGridTextColumn Header="Title" Width="200" Binding="{Binding title}"/>
<DataGridTextColumn Header="isbn" Width="200" Binding="{Binding isbn}"/>
</DataGrid.Columns>
</DataGrid>

step three: fix view model for Binding to work - Binding works with properties:

class BookViewModel
{
public ObservableCollection<Book> Books { get; private set; }

public BookViewModel()
{
Books = new ObservableCollection<Book>();
}
}

step four: implement load data method in the view model amd call it from command, and after mainWin.Show(); to load initial data

Double binding on a WPF DataGrid?

The DataSource of the DataGrid should point to a collection of items.

Each row will be a single entity of your collection and it's properties can then be bound to a column (using templates).

See:
Datagrid binding in WPF

Bind WPF DataGrid to one-dimensional array

You have a one-dimensional array, so how are you expecting it to bind to 3 columns? Think about it, the DataGrid is like a display for a two-dimensional array, the columns are the x axis, and the rows are the y axis. So your one-dimensional array must go in the rows of one column.

EDIT To represent a more complex type as you mentioned in your comments, you can use DataTable if you bind the DataGrid directly to the data (only for very simple projets) or better List<> if you bind to business objects. Here is an example:

Change your class to have the three properties that you want (give them more meaningful name than this example):

public class Cylinder {
public float Vector1 = { get; set; };
public float Vector2 = { get; set; };
public float Vector3 = { get; set; };
}

Now you can bind your DataGrid directly to this class for testing, but in a real application where data is coming from some source like a database, you create a list of this class:

var cylinders = new List<Cylinder>();

And then populate it with the data coming from the database:

foreach(var row in myTable) {
var c = new Cylinder();
c.Vector1 = 4;
c.Vector2 = 5;
c.Vector3 = 6;
cylinders.Add(c);
}

And now you can bind your DataGrid to cylinders. The grid will have three columns representing the three properties of the Cylinder class, and as many rows as you have in myTable.

WPF binding command to Datacontext inside Datagrid

As stated in my comment you need to bind to (ViewModel) Parent/Ancestor.DataContext

Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=DataContext.PreviousPageCommand}"

You'll also need to bind the SelectedItem of your DataGrid so the ViewModel knows which row the button was in when the user clicks. Or bind the DataContext of the button to the CommandParameter. like @Andy mentioned in the comment

DataGridView Column binding in WPF

You can set AutoGenerateColumns to False and take responsibility in your hand to provide the list of columns you want to avoid auto generation of columns when DataSource or DataMember properties are set.

<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding SourceCollection}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Index}"/>
<DataGridTextColumn Binding="{Binding Colour}"/>
<DataGridTextColumn Binding="{Binding Location}"/>
<DataGridTextColumn Binding="{Binding Srno}"/>
</DataGrid.Columns>
</DataGrid>

Binding WPF DataGrid to ListInterface

What this will always only use one of the classes at a time. but when someone changes a combobox it will fire an event that will fill the IList<IReports>.

The way I understand the above is that you never mix different elements inside the list (i.e. it contains only Classes, Students or Cars). All the other answers are assuming the list contains mixed content, but if that's the true, then DataGrid is simply not the right presenter for such content.

If the above assumption is correct, then the only problem is how to represent different lists with a single bindable property. As can be seen in Data Binding Overview, when dealing with collection, data binding does not really care if they are generic or not. The recognizable source types are the non generic IEnumerable, IList and IBindingList. However, the collection view implementation is using some rules to determine the element type of the collection, by seeking for generic type argument of implemented IEnumerable<T> interfaces by the actual data source class, by checking the first available item, or taking the information from ITypedList implementation etc. All the rules and their precedence can be seen in the Reference Source.

With all that in mind, one possible solution could be to change the ReportsTable property type to allow assigning List<Classes> or List<Students or List<Cars>. Any common class/interface will work (remember, data binding will check the actual type returned by GetType()) like object, IEnumerable, IList, IEnumerable<IReports> etc., so I'll choose the closest covariant type to List<IReports which is IReadOnlyList<IReports>:

private IReadOnlyList<IReports> _reportsTable;

public IReadOnlyList<IReports> ReportsTable
{
get { return _reportsTable; }
set { SetProperty(ref (_reportsTable), value); }
}

Now when you do this

viewModel.ReportsTable = new List<Students>
{
new Students { Name = "A" },
new Students { Name = "B" },
new Students { Name = "C" },
new Students { Name = "D" },
};

you get

Sample Image

while with this

viewModel.ReportsTable = new List<Classes>
{
new Classes { ClassName = "A", StudentName = "A" },
new Classes { ClassName = "A", StudentName ="B" },
new Classes { ClassName = "B", StudentName = "C" },
new Classes { ClassName = "B", StudentName = "D" },
};

it shows

Sample Image

and finally this

viewModel.ReportsTable = new List<Cars>
{
new Cars { Mileage = 100, CarType = "BMW", StudentName = "A" },
new Cars { Mileage = 200, CarType = "BMW", StudentName = "B" },
new Cars { Mileage = 300, CarType = "BMW", StudentName = "C" },
new Cars { Mileage = 400, CarType = "BMW", StudentName = "D" },
};

results in

Sample Image

UPDATE: The above requires modifying the model to return concrete List<T> instances. If you want to keep the model as it is (i.e. returning List<IReports>), then you'll need a different solution, this time utilizing the ITypedList. In order to do that, we'll create a simple list wrapper using the System.Collections.ObjectModel.Collection<T> base class:

public class ReportsList : Collection<IReports>, ITypedList
{
public ReportsList(IList<IReports> source) : base(source) { }
public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
{
return TypeDescriptor.GetProperties(Count > 0 ? this[0].GetType() : typeof(IReports));
}
public string GetListName(PropertyDescriptor[] listAccessors) { return null; }
}

then change the bindable property to

private IList<IReports> _reportsTable;
public IList<IReports> ReportsTable
{
get { return _reportsTable; }
set { SetProperty(ref _reportsTable, value as ReportsList ?? new ReportsList(value)); }
}

and you are done.

Data Binding in WPF Data Grid not working

Property IsReadOnly does not see the IsControlUnit field.

You can also use the template for editing and reading.

<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.Header>Control Unit</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding ControllingControlUnit}" Width="200" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding ControllingControlUnit}" IsReadOnly="{Binding IsControlUnit, UpdateSourceTrigger=PropertyChanged}" Width="200" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>

You can also add IsEnabled, then you cannot select text



Related Topics



Leave a reply



Submit