Dynamically add data to columns in GridView - c#

I have the following code that dynamically creates columns within a WPF GridView control, the header names come from a string[] which is stored in a List<string[]> named data_org
GridView gv = tabell.View as GridView;
foreach (string s in data_org.ElementAt(0))
{
gv.Columns.Add(new GridViewColumn { Header = s });
}
Is there a way to add data while I'm creating the columns? I've searched for ways of doing it in the add column statement but can't find a way.
gv.Columns.Add(new GridViewColumn{Header = s, **statement to add data to column**});
My data is stored in another List<float[]>, where each item float[] represents a column. Do I have to do something to handle that data type (float[]), too?

You do not add data items directly to the columns of a GridView. Instead, you set the ItemsSource of the associated ListView, which is tabell in your case.
tabell.ItemsSource = /* Set a binding or assign an items collection. */;
Then you would create bindings for each column to the corresponding properties on your data items that should be displayed in the columns using DisplayMemberBinding.
var gridViewColumn = new GridViewColumn
{
Header = s,
DisplayMemberBinding = new Binding(/* Binding property path / name of the property. */);
};
As you only have a list of floats for each column, you should create a suitable data item type first. The ItemsSource expects a list of items that contain properties for each column, it represents a row.
What you have to do now is:
Create a row data type that contains properties for each column
public class MyDataItem
{
public float Number { get; }
// ...properties for other columns..
}
Create a collection of these data items with data from you float lists.
var myDataItemList = new List<MyDataItem>();
// ...create data items, add your data and add the items to the list.
Assign the list as items source of the ListView.
tabell.ItemsSource = myDataItemList;
Add display member bindings for each column.
var gridViewColumn = new GridViewColumn
{
Header = s,
DisplayMemberBinding = new Binding(nameof(MyDataItem.Number));
};
Then it should work. However, I recommend you to have a look at the MVVM design pattern.

Related

wpf how to edit datagrid row

I'm using datagrid as the temporary list that until I decide to insert in the database all the data remain in datagrid. I'm adding functions like adding new records, deleting or editing. but I can not change selectedrow
my code is
gridlist.Items.Add(new { num_ins = num_ins.Text, dat_ins = DateTime.Now.ToShortDateString()} --> and many other value
and for delete
var selectedItem = gridlist.SelectedItem;
if (selectedItem != null)
{
gridlist.Items.Remove(selectedItem);
}
i want to make something like this
gridlist.Columns[0].gridlist.Items[1]= "my value";
I wanted to know if it is possible to do this directly from the datagrid as a removal or creation of new records
There are two possibilities.
If you always just add an anonymous type to the Items collection, then it is not possible no update the individual column values. You can however, update the entire row
gridlist.Items[0] = new { num_ins = 1, dat_ins = DateTime.Now};
If you could create a class/structure with public properties for the items being added, then you can update the individual properties of the items.
public class temp
{
public int num_ins {get;set;}
public DateTime dat_ins {get;set;}
}
((gridlist.Items[0] as temp)).num_ins = 3;

Fastest way to add to a list elements not in second list

I have 2 listBoxes with BindingLists as their data sources. The idea is to make a List builder (as MSDN names it), where first listBox shows currently added columns and second listBox shows the rest of available columns. First list contains ViewColumn objects, while the other list contains strings.
I load chosen columns into first listBox from database and then I want to load the rest of available columns into the second listBox (the list itself comes from another place in database). Considering there are no limits on the number of columns, I want to do that in the fastest way possible - what would that be?
Here's some code to visualize that:
ViewTable _view;
BindingList<ViewColumn> _viewColumns = new BindingList<ViewColumn>();
BindingList<string> _detailsColumns = new BindingList<string>();
void CustomInitialize()
{
_view = //get view and its columns
_viewColumns = new BindingList<ViewColumn>(_view.Columns);
listBox_CurrentColumns.DataSource = _viewColumns;
listBox_CurrentColumns.DisplayMember = "Name";
var detailsTable = //get the list of available columns
foreach (var row in detailsTable)
{
//TODO: if _viewColumns does not contain this value, add it to _detailsColumns
_detailsColumns.Add(row.ColumnName);
}
listBox_AvailableColumns.DataSource = _detailsColumns;
}
I think you want to do something like:
_detailsColumns = _allColumns.Except(_viewColumns.Select(c => c.Name))
This should get you all entries in the _allColumns collection excluding the entries in the _viewColumns collection.
I assume here that _allColumns contains the overall collection of possible columns.

Insert a blank row into a Datagrid with dynamic columns

I create the columns of my Silverlight DataGrid dynamically in the code behind using a List as follows:
private void BuildQuotationDGColumns(List<ProductCategory> ProdCatList)
{
// add a template column with drop down list of products
DataGridTemplateColumn ProductColumn = new DataGridTemplateColumn();
ProductColumn.Header="Choose Product";
ProductColumn.CellTemplate=(DataTemplate) Resources["ProductDDLTemplate"];
QuotationDG.Columns.Add(ProductColumn);
// for each entity in ProdCatList add a text column
foreach (ProductCategory ProdCat in ProdCatList)
{
DataGridTemplateColumn ProdCatColumn = new DataGridTemplateColumn();
ProdCatColumn.Header = ProdCat.Name;
ProdCatColumn.CellTemplate = (DataTemplate)Resources["MoneyTemplate"];
ProdCatColumn.CellEditingTemplate = (DataTemplate)Resources["MoneyEditingTemplate"];
QuotationDG.Columns.Add(ProdCatColumn);
}
insertDummyRow(ProdCatList);
}
I need to insert a blank row in my Datagrid using insertDummyRow. Since the columns are dynamic and are only known in runtime, I need to create an entity whose attributes can be set in run time.
I thought of converting my ProdCatList into a Class, so that instances of this class would form the grid rows, but I couldn't understand how to do this conversion
EDIT:
Based on Bahman_Aries's solution below,
I'm trying to add data into my row but I'm getting empty row and my data (column.Header.ToString()) isn't added. Here's my code:
CultureInfo provider= new CultureInfo("en-US");
Object[] myrow= new Object[QuotationDG.Columns.Count];
int i=0;
foreach(DataGridColumn column in QuotationDG.Columns)
{
myrow[i] = Convert.ChangeType(column.Header.ToString(), typeof(object), provider);
i++;
}
MyData.Add(myrow);
QuotationDG.ItemsSource = MyData;
Can you point me on what i'm doing wrong?
This is the implementation for the Grid Templates:
<UserControl.Resources>
<DataTemplate x:Key="MoneyTemplate">
<TextBlock></TextBlock>
</DataTemplate>
<DataTemplate x:Key="MoneyEditingTemplate">
<TextBlock></TextBlock>
</DataTemplate>
<DataTemplate x:Key="ProductDDLTemplate">
<ComboBox />
</DataTemplate>
</UserControl.Resources>
Okey, let me clear up some confusion before we proceed:
Since the columns are dynamic and are only known in runtime, I need to
create an entity whose attributes can be set in run time.
Not necessarily, you can use a list of objects.
I thought of converting my ProdCatList into a Class, so that instances
of this class would form the grid rows
There is no need to create a complex data structure just to insert a blank row into the DataGrid, something as simple as QuotationDG.Items.Add(""); will do.
So from what I understand, either you're overcomplicating the issue or you did not provide enough information and I'm oversimplifying it! (If so please let me know so I can correct this straight away).
Anyhow, Since you defined a CellEditingTemplate I assume your grid cells are editable, therefore you can not use QuotationDG.Items.Add because it'll prevent editing. Instead you should define a list, add your data to it and then use it as ItemsSource of your DataGrid:
// Your data source
ObservableCollection<object[]> MyData = new ObservableCollection<object[]>();
// Insert a blank row into the data source
private void insertDummyRow()
{
MyData.Add(new object[QuotationDG.Columns.Count]);
QuotationDG.ItemsSource = MyData;
}
Edit:
Since there is no data-binding in your CellTemplates, nothing can be seen in your DataGrid. For this to work, when columns are creating dynamically you need to add corresponding DataBindings as well:
// Sample drop down list of products to show
public ObservableCollection<string> ProductList = new ObservableCollection<string> { "Item1", "Item2", "Item3" };
private void BuildQuotationDGColumns(List<ProductCategory> ProdCatList)
{
// Define a DataGridComboBoxColumn
DataGridComboBoxColumn prodComboColumn = new DataGridComboBoxColumn();
// Bind this column to the first item of the DataGrid.ItemsSource (e.g. MyData[0])
prodComboColumn.SelectedItemBinding = new Binding("[0]");
// Set ProductList as the ItemsSource of DataGridComboBoxColumn
prodComboColumn.ItemsSource = ProductList;
prodComboColumn.Header = "Choose Product";
QuotationDG.Columns.Add(prodComboColumn);
// For each entity in ProdCatList add a text column
int i = 1;
foreach (ProductCategory ProdCat in ProdCatList)
{
// Define a DataGridTextColumn
DataGridTextColumn ProdCatColumn = new DataGridTextColumn();
ProdCatColumn.Header = ProdCat.Name;
// Bind this column to the i-th item of the DataGrid.ItemsSource (e.g. MyData[i])
ProdCatColumn.Binding = new Binding(string.Format("[{0}]", i));
QuotationDG.Columns.Add(ProdCatColumn);
i++;
}
insertDummyRow();
}
To see if UI shows any data, you can try my modified version of your add-data procedure:
private void Button_Click(object sender, RoutedEventArgs e)
{
CultureInfo provider = new CultureInfo("en-US");
Object[] myrow = new Object[QuotationDG.Columns.Count];
int i = 0;
foreach (DataGridColumn column in QuotationDG.Columns)
{
if (column is DataGridComboBoxColumn)
myrow[i] = Convert.ChangeType(ProductList[0], typeof(object), provider);
else
myrow[i] = Convert.ChangeType(column.Header.ToString(), typeof(object), provider);
i++;
}
MyData.Add(myrow);
QuotationDG.ItemsSource = MyData;
}
To be sure that data entered by user is going to update the source (e.g. MyData) as well, set a break-point and check MyData for any changes after editing data-grid cells manually.

Setting DataSource to DataGridViewComboBoxColumn

I'm trying to set DataSource to DataGridViewComboBoxColumn of my DataGridView. First I'm trying to bind a data source to my DataGridView, where bindingList is a List of my custom class Plugin with properties Name (string), Id (string) and Dependencies (List):
var bindingList = PluginsHandler.GetPlugins();
var source = new BindingSource(bindingList, null);
pluginsDataGridView.AutoGenerateColumns = false;
pluginsDataGridView.DataSource = source;
pluginsDataGridView.Columns["pluginName"].DataPropertyName = "Name";
pluginsDataGridView.Columns["pluginID"].DataPropertyName = "Id";
So I can set my first two columns, but now I want to bind data to a third column of type DataGridViewComboBoxColumn. I try to do it on DataBindingComplete event:
private void pluginsDataGridView_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
for (int i = 0; i < pluginsDataGridView.Rows.Count; i++)
{
var comboCell = (DataGridViewComboBoxCell) pluginsDataGridView.Rows[i].Cells["pluginDependencies"];
var entry = pluginsDataGridView.Rows[i].DataBoundItem as IPlugin;
comboCell.DataSource = entry.Dependencies;
}
}
Sadly comboBox is empty. Funny thing happens when I incorrectly put these lines after the first block of code I posted:
var dependenciesColumn = (DataGridViewComboBoxColumn) pluginsDataGridView.Columns["pluginDependencies"];
dependenciesColumn.DataPropertyName = "Dependencies";
Then binding seem to start to work, as I can see that there are some entries in comboboxes, but when I try to hover mouse on combobox, I am getting an error that says DataGridViewComboBoxCell value is not valid).
How can I make it work?
Instead of assigning each ComboCell a data Source, set the DataSource of the column. I assume the Dependencies property of PlugIn class is a List<string>.
pluginsDataGridView.Columns["pluginDependencies"].DataSource = //list of dependencies
You have to set the DataPropertyName of the Dependencies ComboBoxColumn to get the initial values. If you don't set it you won't see any value in the column when the application is loaded.
pluginsDataGridView.Columns["pluginDependencies"].DataPropertyName = "Dependencies"
Edit:
You have a list of dependencies for a plug-in. i.e, more than one value. Usually, to select one value from list of values, you associate list with ComboBoxColumn. Achieving your requirement of multiple values from a list using standard ComboBoxColumn is difficult. Write a custom CheckedComboBoxColumn where you can display and select multiple values.

Cdd data to column series in wpf C#

I want to create a ColumnSeries Bar Chart in WPF using C#. I shall extract the data from the database and want to bind it to the bar chart.
The data extracted will contain two values. First is parameter name (string) and the other is its value (double). Which type of collection shall I use? and how to do the binding?
i finally used a simple KeyValuePair array and assigned it to the ItemsSource property of the ColumnSeries of barchart.
Just use the Dictionary as follows:
Dictionary<string,int> data = new Dictionary<string,int> ();
If you have a data in dataset then use foreach loop for item in the dataset
Example:
foreach (DataRow drv in DS.Tables[0].Rows)
{
string strvalue= Convert.ToString(drv["columnname string type"]);
string intvalue= Convert.ToString(drv["column name int type"]);
data.Add(Convert.ToString(strvalue), Convert.ToInt32(intvalue));
}
((ColumnSeries)msChart3.Series[0]).ItemsSource = data;
This way you can bind data to a column series chart type.

Categories

Resources