Getting the current object with BindingContext is no problem but what do I do when I have selected many rows in the datagridview? How do I iterate through each object?
This wasn't easy or fun. Binding multiple selected rows in the datagrid isn't supported by default. I use MultiSelectBehavior from Functional Fun:
http://blog.functionalfun.net/2009/02/how-to-databind-to-selecteditems.html
These are my notes to get it to work:
To get this to work, I did this:
Add this namespace definition to the view:
xmlns:ff="clr-namespace:FunctionalFun.UI.Behaviours;assembly=MultiSelectBehavior"
Within the datagrid, add the last two lines shown here (ff:... and SelectionMode....):
ff:MultiSelectorBehaviours.SynchronizedSelectedItems="{Binding SelectedTasks}"
SelectionMode="Extended"
Note: In the view model, SelectedTasks cannot be null, even when first declared.
No:private ObservableCollection selectedTasks;
Yes: private ObservableCollection selectedTasks = new ObservableCollection();
And this is some actual code that works:
xmlns:ff="clr-namespace:FunctionalFun.UI.Behaviours;assembly=MultiSelectBehavior"
<DataGrid Grid.Row="1" AutoGenerateColumns="False" IsReadOnly="True" HeadersVisibility="Column"
ItemsSource="{Binding SelectedApplicationServer.ApplicationsWithOverrideGroup}"
ff:MultiSelectorBehaviours.SynchronizedSelectedItems="{Binding SelectedApplicationsWithOverrideGroup}"
SelectionMode="Extended">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=Application.Name}" Header="Name" Width="150" />
<DataGridTextColumn Binding="{Binding Path=Application.Version}" Header="Version" Width="100"/>
<DataGridTextColumn Binding="{Binding Path=CustomVariableGroup.Name}" Header="Override Group" Width="*"/>
</DataGrid.Columns>
</DataGrid>
Hope it helps.
Edit: I simply added the Functional Fun code as a project within my solution, and then I referenced it within my view project:
Assuming your DataGridView is bound to a BindingSource, using the DataMember property this way :
myDataGridView.DataSource = someBindingSource;
myDataGridView.DataMember = "SomeCollectionProperty";
Then you can retrieve the list of bound items behind your DataGridView:
IList dataBoundItems =
((CurrencyManager)grid.BindingContext[grid.DataSource, grid.DataMember]).List;
You may also want to cast this list to an IEnumerable<T> using :
var myItems = dataBoundItems.OfType<myClass>();
Related
I am new to WPF and data binding. I an trying bind a list of strings to a row on a data grid column, Animals, in WPF. I'm not sure what I am doing wrong, but the column shows up as blank when I run the solution. To add rows this way instead of using a DataTable and looping through the list and adding the rows because the next column I am adding will be of type Combobox so I didn't wanna implement Ui elements into the DataTable.
public List<string> Animals {get; set;} = new List<string>
{
"Dogs",
"Cats",
"Birds"
};
<DataGrid
filtergrid:DataGridExtensions.UseBackgroundWorkerForFiltering="True"
filtergrid:DataGridExtensions.IsFilterVisible="True"
filtergrid:DataGridExtensions.IsClearButtonVisible="False"
ColumnHeaderStyle="{StaticResource {ComponentResourceKey
TypeInTargetAssembly={x:Type filtergrid:DataGridHeaderFilterControl},
ResourceId=DataGridHeaderFilterControlStyle}}"
AutoGenerateColumns="False"
ItemsSource="{Binding}"
CanUserAddRows="False"
HorizontalAlignment="Stretch"
Margin="10,50,0,0"
HorizontalScrollBarVisibility="Auto">
<DataGrid.Columns>
<DataGridTextColumn Header="Animals" Width="Auto"
Binding="{Binding Animals}" IsReadOnly="True" />
</DataGrid.Columns>
</DataGrid>
Your code seems right but in order to show something I think you need to do a selection.
So you could bind a property to SelectedIndex which is set to 0 or whatever you like.
I am trying to bind a combobox to a dictionary.
"Phases" is a dictionary inside ProjectPlans class
public Dictionary<decimal?, string> Phases { get; set; }
Instead of displaying the values, combobox shows just word "(Collection)" and no dropdown arrow. What am I missing?
<c1:C1DataGrid ItemsSource="{Binding ProjectPlans}" IsReadOnly="True" RowDetailsVisibilityMode="VisibleWhenSelected">
<c1:C1DataGrid.Columns>
<c1:DataGridBoundColumn Header="ID" Binding="{Binding ProjectId}" />
<c1:DataGridComboBoxColumn Header="PHASE" Binding="{ Binding Phases}" DisplayMemberPath="Value" SelectedValuePath="Key"/>
I have found a workaround by using a DataTemplateColumn instead. But I still do not understand why it doesn't work with a DataComboBoxColumn. A bug?
I'm using a DataGrid (Not a DataGridView) to display some info, and once I press a, say a save button I want all the data to be moved to a listbox column wise...
Help's appreciated guys! :D
EDIT: (here's the code so I want the data from the columns below to be read)
I tried this : MessageBox.Show(SMLDataGrid.Items[0].ToString());
There's no .Value option either... or anything similar that I've seen
<DataGrid x:Name="SMLDataGrid" CanUserSortColumns="True" CanUserAddRows="False" AutoGenerateColumns="False"
materialDesign:DataGridAssist.CellPadding="13 8 8 8" materialDesign:DataGridAssist.ColumnHeaderPadding="8" VerticalAlignment="Top">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding BaseIn}"
Header="Base" x:Name="GrammarBaseColumn"
EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnEditingStyle}"/>
<DataGridTextColumn Binding="{Binding PastIn}"
Header="Past Form" x:Name="GrammarPastColumn"
EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnEditingStyle}"/>
<DataGridTextColumn Binding="{Binding PastPIn}"
Header="Past Participle Form" x:Name="GrammarPastPColumn"
EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnEditingStyle}"/>
<DataGridTextColumn Binding="{Binding IesIn}"
Header="Plural Form" x:Name="GrammarIngColumn"
EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnEditingStyle}"/>
<DataGridTextColumn Binding="{Binding IngIn}"
Header="Verb Form" x:Name="GrammarIesColumn"
EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnEditingStyle}"/>
</DataGrid.Columns>
</DataGrid>
EDIT:I've tried assigning the ItemSource of the DataGrid upon the Save Button press to another list as well through this:
ListBox a = new ListBox();
a.ItemsSource = SMLDataGrid.Items;
MessageBox.Show(a.Items[0].ToString());
But the messagebox shows the name of the file + name of the class that holds all the strings..
You have probably set the ItemsSource property of the DataGrid to an IEnumerable<YourClass> (if you haven't you should) where YourClass is the class where the BaseIn, PastIn, PastPIn, ... properties are defined.
You can set the ItemsSource of the ListBox the same way:
listBox.ItemsSource = SMLDataGrid.ItemsSource;
var ic = SMLDataGrid.Items.OfType<YourClass>().ToList();
MessageBox.Show(ic[0].BaseIn);
The ListBox has no concept of columns though but depending on what you are trying to do you could use a ListView with a GridView instead: http://www.wpf-tutorial.com/listview-control/listview-with-gridview
My problem is this:
I use EF code first and I got a master detail situation, the master have a childs wich are the itemsSource for a datagrid, like this:
<DataGrid ItemsSource="{Binding Path=Transaction.StockItems,Mode=TwoWay}"
SelectedItem="{Binding Path=StockItem, Mode=TwoWay}"
AutoGenerateColumns="False" IsReadOnly="True">
<DataGrid.Columns>
<mui:DataGridTextColumn Width="0.12*" Binding="{Binding Name}"/>
<mui:DataGridTextColumn Width="0.12*" Binding="{Binding Cod}"/>
<mui:DataGridTextColumn Width="0.12*" Binding="{Binding Cost}"/>
<mui:DataGridTextColumn Width="0.15*" Binding="{Binding Qt}"/>
</DataGrid.Columns>
</DataGrid>
In my ViewModel I got a property for the Transaction property, like this:
private tTran_t;
public tTransaccion Transaction
{
get { return _t; }
set { _t= value; RaisePropertyChanged("Transaction"); }
}
In other method of my ViewModel I do an Add() to the collection, like this:
Transaction.StockItems.Add(myNewLine);
RaisePropertyChanged("Transaction");
In my Model the definition of Transaction.StockItems is ICollection.
The problem: the datagrid never got updated
I guess this is because the RaisPropertyChanged() is never called, because the collection is never set, but as you can see, I do call the RaisPropertyChanged() of the Transaction object.
Thanks in advance
adding an item to a collection doesn't "change" the object itself. a RaisepropertyChanged is raised when the collection itself is set. so what you need to do is assigning a new collection to your collection reference. So First you add item to a temporary collection then you do transaction = new collection(temporaryCollection) then your UI will ne notified of a change.
Actually, I have a small wpf application which have a DataGrid window that I could not fill it with objects.
In my ViewModel class I have this:
public class UserViewModel : INotifyPropertyChanged
{
public UserViewModel()
{
User myUser = new User();
}
...
}
Note that the Object myUser have 3 properties: ID, Name, and Notes which is a list containing other properties : NoteID, NoteTitle, NoteDescription.
<Window.DataContext>
<local:UserViewModel/>
</Window.DataContext>
<DataGrid Name="noteDataGrid" ItemsSource="{Binding DataContext}" AutoGenerateColumns="True">
<DataGrid.Columns >
<DataGridTextColumn Binding="{Binding Path=NoteID}" Header="ID"/>
<DataGridTextColumn Binding="{Binding Path=Title}" Header="Title"/>
<DataGridTextColumn Binding="{Binding Path=Description}" Header="Desc"/>
</DataGrid.Columns>
</DataGrid>
That's it, I know that there is something that does not match, but this is my first WPF (MVVM) Application, that's why i'll be so glad to have a solution.
Best Regards
In your VM you have to expose some collection, say, List<User> Users. Important: it must be a property.
Then just add items to this collection in your constructor.
Bind to the collection to DataGrid this way: ItemsSource="{Binding Users}".
Voila.
Also, AutoGenerateColumns="True" will duplicate your columns (you add them both manually and automatically).