Add columns and rows to wpf listview dynamically - wpf

i want to add new columns and rows to a C# WPF ListView (GridView) at runtime. As far as i know you can only add rows to a gridview by using anonymous objects or classes with a static set of members to which the columns are bound. Is there a way to do this at runtime that the user is able to add a new column, bind this column to something and add new data?
thx
ooorndtski

Yes, you can do this in code an runtime. You need the GridView as a variable (give it a name in XAML to auto-generate that variable in Visual Studio). The GridView has a Columns property that you can handle like any other collection, you can add and remove for example.
This is the example from MSDN (The gridview name "myGridView"):
GridViewColumn gvc3 = new GridViewColumn();
gvc3.DisplayMemberBinding = new Binding("EmployeeNumber");
gvc3.Header = "Employee No.";
gvc3.Width = 100;
myGridView.Columns.Add(gvc3);
Generally speaking, anything you can do in XAML, you can do in code.

So, what i was looking for is described in this thread.
He creates a new Dictionary-class, which implements the INotifyPropertyChanged interface.
When adding data to the dictionary an event is triggered.
At the place in your code where you want to add a new row, you just put the data into an object of this Dictionary class and add the Dictionary to an ObservableCollection which is bound to the DataGrid.

Related

WPF MVVM : get a collection of cell-data corresponds to a column

Is there any way to get DataGridColumns cells-data as a collection of cell-data corresponds to this column?
Note that I'm using MVVM and my datagrid is being dynamically built by DataGridColumn collection!
Thanks!
If you are really using MVVM, then you will know that you should have all of the data that is displayed in the view in your related view model. If that is correct, then you will have a collection that is data bound to the DataGrid.ItemsSource property. As we work with data in WPF and not UI elements, then you can get a collection that contains all of the values from one column using LinQ.
Let's say that you have a column (and therefore a property of your data type) that you want to single out. Let's say that that property is a string and named Name. You can gather all of the values of that property from each item in the collection like this:
List<string> names = yourCollection.Select(i => i.Name).ToList();
If it were an int property named Age, you could do this... and so on:
List<int> ages = yourCollection.Select(i => i.Age).ToList();

DataGrid relocate add new row to the top

In a DataGrid view, the blank row add entries is convenient but quickly get's lost when the list is large. Can you change it's default location from the bottom to the top of the DataGrid view?
I've rarely used a DataGrid and know nothing about its ability to add rows, but coming from a WPF/MVVM point of view, you don't need that anyway. Generally in WPF/MVVM, we manipulate data rather than UI controls, so the solution is easy. First we Bind our collection of data (in whatever shape we chose) to the DataGrid.ItemsSource property:
public ObservableCollection<DataItem> SomeDataCollection { get; set; }
...
<DataGrid ItemsSource="{Binding SomeDataCollection}" ... />
Now, if we want to add a new item to the bottom of the DataGrid we can do this in the code behind/view model:
SomeDataCollection.Add(new DataItem());
Then if we want to add a new item to the start of the collection, we can just do this:
SomeDataCollection.Insert(0, new DataItem());
Of course, you'll need to implement the INotifyPropertyChanged interface in your code behind/view model to make this work, but (hopefully) you'll be doing that anyway.
UPDATE >>>
Sorry, I misunderstood you. I found a NewItemPlaceholderPosition Enumeration on MSDN that is used by an ItemCollection.IEditableCollectionView.NewItemPlaceholderPosition Property. Unfortunately, those linked pages don't have an code examples, so I found one in the in wpf datagrid how to get the blank row on top? post here on StackOverflow. From the answer by #woodyiii in that post:
var view = CollectionView.GetDefaultCollectionView(EmployeeList)
as IEditableCollectionView;
if(view!=null)
view.NewItemPlaceholderPosition = NewItemPlaceholderPosition.AtBeginning;
This does mean that you'd have to use a CollectionView to get this to work, but it seems like the only way... the NewItemPlaceholderPosition Enumeration isn't used by anything apart from the various CollectionView classes.
This worked for me:
IEditableCollectionView cv = (IEditableCollectionView)grdSchedule.Items;
cv.NewItemPlaceholderPosition = NewItemPlaceholderPosition.AtBeginning;
Where grdSchedule is the the name of your DataGrid

WPF: New Row on Datagrid that bind to custom class

I created some custom data container class with OnPropertyChanged event and ObservableCollection and bind it to datagrid in WPF. The problem is everytime the program start, the datagrid automatically creates a new row at the bottom. This new row is not present in my ObservableCollection so editing it will be useless, as adding new item programmatically in my ObservableCollection will erase the data in the new row.
How can I disable the new row or make my ObservableCollection updated if user start editing in new row (just like in SQL Server management Studio)?
nb: If you can please give me an example of "correct" custom class in WPF, I'm still in WPF.
Meleak's answer from comment:
If you just want to disable that users can add new rows then set CanUserAddRows="False" in the DataGrid. The NewItemPlaceHolder that is the empty row, will be inserted into the ObservableCollection upon commit.

After adding a new row why aren't my bound controls updating?

I'm using wpf drag and drop databinding to datasets. I generate a new datatable row using the AddNew method of the BindingListCollectionView. I set values on the new row and call CommitNew on the BindingListCollectionView. I expect to see my assigned values in the bound controls but they are all blank. If I save the changes to the database the controls are then updated, but I want the user to see my assigned values before calling UpdateAll on the TableAdapterManager.
Background:
I've created a strongly typed dataset in a project separate from my wpf application. My wpf app references the dataset application. I added an object datasource in the wpf app pointing to the typed dataset. I dragged fields/controls from the datasources window to the wpf designer window. The generated xaml includes a Window.Resources section with a CollectionViewSource accurately bound to my dataset and datatable. This CollectionViewSource is the DataContext for the controls that I dragged to the design surface. All of the controls use TwoWay databinding.
When the window loads I grab a reference to the xaml's CollectionViewSource (using FindResource). I then grab a reference to the view property of the CollectionViewSource and cast it to a BindingListCollectionView. Now I use the AddNew method of the BindingListCollectionView to generate a new row (which AddNew returns as an object). I cast the object to a DataRowView and access it's Row property. I then cast the row to a strongly typed datatable row (generated by the DataSet designer). Now I assign values to some of the datatable row columns. I call CommitNew on the BindingListCollectionView. Finally I call MoveCurrentToFirst on the CollectionViewSource.
Problem:
Using a watch expression I can see the data is in the SourceCollection of both the CollectionView and the BindingListCollectionView. Can anyone explain why the bound controls do not show the data unless I save the changes to the database?
Code (generated XAML not shown):
Private WithEvents _cvsScanData As System.Windows.Data.CollectionViewSource
Private WithEvents _blcvScanData As System.Windows.Data.BindingListCollectionView
_cvsScanData = CType(Me.FindResource("Dt_tblScanDataViewSource"), System.Windows.Data.CollectionViewSource)
_blcvScanData = CType(_cvsScanData.View, BindingListCollectionView)
Dim newRow As LabDataSet.dt_tblScanDataRow = CType(CType(_blcvScanData.AddNew, System.Data.DataRowView).Row, LabDataSet.dt_tblScanDataRow)
newRow.SampleID = "testSampleID"
newRow.MachineID = "testMachineID"
_blcvScanData.CommitNew()
_cvsScanData.View.MoveCurrentToFirst()
The simple fix is to call the Refresh method of the BindingListCollectionView after calling CommitNew.
_blcvScanData.Refresh()
I stumbled across this answer to my own question via intellisense. If anyone can explain why refresh is necessary I'd appreciate it. I expected the INotifyPropertyChange interface to update the bound controls obviating the need to call refresh.

Silverlight 3 Dataform - how to add fieds at runtime

I am creating a DataForm from dynamic data (so I can't create the columns in the xaml), I currently create columns for my DataGrid (I have not worked out how I can create a button + event in a colomn yet)
foreach (var item in headings.Entities)
{
theDataGrid.Columns.Add(
new DataGridTextColumn
{
Header = item.Label,
Binding = new Binding(item.LocalName)
});
}
I cannot see any methods to add fields to a DataForm at runtime, however...
You'd be better off not creating your datagrid columns in code, but using bindings instead. Just bind the datagrid to the headings.Entities collection.
The same thing with your DataForm, just bind your item to it and it should create all the proper fields for you.

Resources