How to display a List of Strings as a DataGrid (table) in XAML and C# - c#

I've been a long time lurker on SO and have only recently decided to set up an account. I've been spending quite a lot of hours trying to solve this problem I've been having without asking but I here it is.
What I'm trying to accomplish:
I have a list of strings, e.g: Mango, Banana, Melon (let's call it fruits) and I want to display it as a table in XAML (WPF), where it appears as row values on the left side, and the right side will be combo boxes that will allow users to pick a value. I'm currently stuck on the displaying part of this problem. I decided to use a DataGrid to display the list, and the code behind will do the data bindings.
Here's the XAML part of it:
<DataGrid x:Name="FruitDataGrid" Height="265" VerticalAlignment="Center" Margin="-7,8,-2,-6" HorizontalAlignment="Left" Width="1188" AutoGenerateColumns="False">
<!-- If AutoGenerateColumns was true only the length is displayed.-->
<DataGrid.Columns>
<DataGridTextColumn x:Name="fruitsDisplay" Header="Fruits" MinWidth="450" IsReadOnly="True" />
<DataGridComboBoxColumn Header="Number of Boxes" MinWidth ="200" CanUserResize="True" Width="*"></DataGridComboBoxColumn>
</DataGrid.Columns>
Code Behind so far has been really simple, and after many attempts this is the most recent one.
private void populateFruitList()
{
FruitDataGrid.DataContext = fruitDataTable;
//Binds a datatable instance to the datagrid, does not display anything.
}
What I've been attempting:
Turn the List of Strings into an Observable Collection, or Enumerable, and do FruitDataGrid.itemsource = fruitsObservable;
The above method works, except that it will only display the length of each string value (if autogeneratecolumns is true), which is not what I want. If autogeneratecolumns was false then I can see the rows being shown, but not the string values.
I also tried using DataView or DataGridView but I failed to define it in the XAML, VS2012 says that there isn't such a thing.
I've been trying to do data binding as well as the MSDN Article says, but VS2012 never manages to bind to the list properly.
I then attempted to change my list into a datatable and [use a datagridview as specified here but again the XAML tells me it is not a valid class][2]. I am also aware of the performance impact datagridview might have but at this point I just want to display a table really.
I've also seen that some tutorials use a DataGrid.datasource method but that isn't in the DataGrid I want, I think it's a different class? (the DataGrid I am attempting to use is System.Windows.Controls.DataGrid, and the other one is in Windows Forms [As shown here][3])
Thanks again for taking the time to look into this.
EDIT
Trying to bind to the list in XAML this way:
<DataGrid x:Name="FruitDataGrid" Height="265" VerticalAlignment="Center" Margin="-7,8,-2,-6" HorizontalAlignment="Left" Width="1188" AutoGenerateColumns="False" ItemsSource="fruitDataList">
I get the error in XAML "The type converter for IEnumerable does not support converting from a string" which I think is because I'm doing it wrong. The table now shows a lot of empty rows though.
Trying ItemSource="{Binding fruitDataList}" (where fruitDataList is a List) yields a blank table, and an error in VS for BindingExpression path error.

To sum up what the previous issue was, thanks to Muds, and hours of trying, the Binding in the XAML was not properly done.
In FruitDataGrid, this property should be written as ItemSource="{Binding}" this tells the XAML code to bind to whatever object the DataContext is assigned to in the code behind.
After that, within the DataGrid.Column, this property is needed.
Binding="{Binding Path=.}"
It had to be exactly that for me. lack of the dot or not enclosing it in quotes will not display the fruits.
Thus, for clarity:
In the XAML:
<DataGrid x:Name="FruitDataGrid"
Height="265" VerticalAlignment="Center" Margin="-7,8,-2,-6"
HorizontalAlignment="Left" Width="1188"
AutoGenerateColumns="False"
ItemSource="{Binding}">
<!-- If AutoGenerateColumns was true only the length is displayed.-->
<DataGrid.Columns>
<DataGridTextColumn
x:Name="fruitsDisplay"
Header="Fruits" MinWidth="450"
IsReadOnly="True"
Binding="{Binding Path=.}"/> <!--Exactly like this -->
<DataGridComboBoxColumn
Header="Number of Boxes"
MinWidth ="200"
CanUserResize="True" Width="*" />
</DataGrid.Columns>
And then in the codebehind (filename.xaml.xs)
//Anywhere you plan to bind the list in my case FruitList
List<string> fruitList = new List<string>();
fruitList.add("Melon");
fruitList.add("Mango");
fruitList.add("Banana");
FruitDataGrid.DataContext = fruitList;
And now you'll have a very nice list displayed as a table. What killed 2 days of my time was the binding path should have a . (dot) right there, and I was binding to a string instead of an object (you literally bind to a string "fruitList" when you do Binding = {"fruitList"}. This amateur mistake stems from me insufficiently self-learning XAML.
Thanks again, Muds. I'll select yours as the answer because it helped me, and it feels weird accepting my own answer.

Considering your binding is set to your viewmodel correctly.. do this
ItemsSource="{Binding fruitDataList}"
then
<DataGrid.Columns>
<DataGridTextColumn
x:Name="fruitsDisplay"
Binding="{Binding Path=FRUITS_PROPERTY_NAME_IN_COLLECTION}"
Header="Fruits"
MinWidth="450"
IsReadOnly="True" />
<DataGridComboBoxColumn
ItemsSource="{Binding TO_List_of_Numbers}"
Header="Number of Boxes"
MinWidth ="200"
CanUserResize="True" Width="*"></DataGridComboBoxColumn>

Related

WPF single Click CheckBox on writeprotected DataGrid

I have found many, many sugestions quite close to my question, but they all seem to be 'dirty hacks'.
My program displays a List of orders. The user should be able to mark orders from that list, and then save that selection to be later informed when the order arrives.
The DataGrid is bound to a DataTable Object, and with the writing enabled DataGrid it is working as intended, except for 2 things:
The user has to click two times, once for selecting the row, and then a second time to switch the checkbox
The usr can edit other fields in the datagrid which is not intended. Furthermore he can add rows to the datagrid, which might bring me to agony city regarding the database.
My goal is that the felds in the Datagrid are NOT changeable with the exception of the checkbox cell. I dont care if the user has to click the checkbox, the cell or even just the row to trigger the change but the change should be done in a single click.
Can someone hint me on that, I have lost the capacity to rate and evaluate all the different aproaches I mentioned earlier.
Kind regards.
For the Checkbox Column create a Template Colum with an Checkbox inside. Then bind the Checkbox.IsChecked to your bound value. You can also set some Columns read only. In Code you only must set an Itemssource for your Datagrid.
Heres some XAML
<DataGrid AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Row1" Binding="{Binding r1Value}" IsReadOnly="True"></DataGridTextColumn>
<DataGridTemplateColumn Header="CB" IsReadOnly="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding PropertyIsChecked}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>

is it possible to bind a datagrid to a object

I would like to bind a DataGrid to an object, and not to a collection of objects,
My scenario is,
I have a single record with a few columns in the database that the user will keep updating,
and for UI design purposes we would like the user to update it through a DataGrid with a single row. As a work around, I created an ObserverbaleCollection and added that record,
but I would like to do it the right way so please if someone could guide me.
Thanks
p.s.
as requested Below
here his the xaml for the datagrid i tried
<DataGrid CanUserAddRows="False" IsReadOnly="False" AutoGenerateColumns="False" ItemsSource="{Binding FacilityDefaults}">
<DataGrid.Columns>
<DataGridTextColumn Header="Price " Binding="{Binding Price,UpdateSourceTrigger=LostFocus}"/>
<DataGridTextColumn Header="Default Temperature" Binding="{Binding DefaultTemperature,UpdateSourceTrigger=LostFocus}"/>
</DataGrid.Columns>
</DataGrid>`
Using a Datagrid as an edit mechanism for a single record seems like the wrong choice in the first place. A Datagrid is made to work with a collection of items not really a single item. But if you insist on using it in this manner, then binding to a collection with just your one record in it is the simplest way to make it work. A DataGrid's ItemsSource expects an IEnumerable (MSDN), so binding it to a single object would be awkward to say the least.

WPF DataGrid crash on cell click

I have a simple window with a simple DataGrid on it. The window has a ViewModel which contains a public property ObservableCollection that I use for binding the ItemsSource. This is the code that I use. Very, very basic.
PluginsView pv = new PluginsView();
pv.ShowDialog();
This is the XAML of my DataGrid which gets populated. I have tried also with Mode=TwoWay without any luck.
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Plugins}"
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" Header="Name"/>
<DataGridTextColumn Binding="{Binding DllName}" Header="DllName"/>
</DataGrid.Columns>
</DataGrid>
When I click on a cell to edit the data, I receive the following error and my program crashes. I don't use any styles. Everything is default. It crashes on pv.ShowDialog(); line.
Cannot set OverridesDefaultStyle property in the default Style.
I have tried anything that I know, but I can't solve this error. Can you please share some suggestions to try because this is getting ridiculous. Thank you.
I have found the problem. I had a global style for TextBox and when I was clicking on a datagrid cell, it tried to override the TextBox style of the DataGrid cell with the global one, causing that exception. Two days of work lost with this problem. SOLVED by setting a Key to the global style.

WPF Newbie - How do I store the entire Binding object in a Row of the DataGrid?

I am new to WPF, so there may be an easy answer to this, but it isn't obvious to me.
The grid obviously represents a collection of my Configured Port objects. I want to store the Configured Port object (which is the Binding for each row) in order to pass it to the next UserControl in the MVVM chain when a grid cell is clicked.
I did find this SO question, but the commented section is exactly what I am missing.
Thanks in advance, I'm sure there is an easy solution.
I would use this (everything except for the inner most xaml was taken from the other SO post you linked to:
<DataGrid ItemsSource="{Binding}" AutoGenerateColumns="False" >
<DataGrid.Columns>
<DataGridTemplateColumn Header="Custom Column">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Tag="{Binding}" Content="Click Me" Click="Button_ClickHandler"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridtemplateColumn>
</DataGrid.Columns>
</DataGrid>
Then the source for the click handler:
private void Button_ClickHandler(object sender, EventArgs e)
{
var clickedConfiguredPort = ((FrameworkElement)sender).Tag as ConfiguredPort;
DoStuff(clickedConfiguredPort);
}
Check out this article:
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/1b694f75-7621-4c88-8055-6c31c601c87f/
When I did it, I had predefined columns so I used the second solution, but if you are wanting to auto generate the columns, you could implement the first solution.

Manually add rows in WPF DataGrid

I have the following XAML Code:
<sdk:DataGrid Margin="58,8,52,18" Name="dataGridTickets">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn x:Name="ticketNoColumn" Header="Ticket No." IsReadOnly="True" Width="SizeToHeader"/>
<sdk:DataGridTextColumn x:Name="seatRowColumn" Header="Seat Row" IsReadOnly="True" Width="SizeToHeader"/>
<sdk:DataGridTextColumn x:Name="seatNumberColumn" Header="Seat Number" IsReadOnly="True" Width="SizeToHeader"/>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
I would like to enter manual data into the grid programatically, how can I manage to do this?
Thanks
Working Solution
Programatically add rows in a WPF DataGrid
You don't add rows to a grid.
Bind the Grid to a List (Observable collection)
Add items to that list.
Result: new rows show up in the grid.
If you don't want to databind the datagrid (even at runtime), you can follow the advice in this SO article:
programmatically add column & rows to WPF Datagrid
Basically you create a new row (in code) and populate it with items and then assign it to your grid.
Like Henk pointed out though, it isn't a great practice. If this is a one-off situation, there may be justification for it but in general you should approach it by updating the underlying data source. Here is an example from Microsoft:
http://social.msdn.microsoft.com/Forums/en/wpf/thread/9b96a798-e185-4d90-ba73-afc35eb91643

Categories