I am new to WPF. I want to delete row from datagrid runtime.When I try to delete row like this
Datagrid.Items.Remove(eRow);
It gives me an error " The error is: Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource instead."
I read online that you could use ObservationCollection and InotifyPropertyChangedEvent but I dont know how to implement it.
I have remove button like this
This is datagrid
<ctrls:RhinoDataGrid x:Name="dataGrid" Grid.Row="1" Margin="5" ItemsSource="{Binding Model.CurrentDataTable}"
Style="{StaticResource RhinoDataGridBaseStyle}" IsReadOnly="{Binding Model.IsLinkFile}"
SelectedValue="{Binding Model.CurrentDataRow}" SelectedValuePath="Row"
>
</ctrls:RhinoDataGrid>
Pls help me. Thanks.
Your DataGrid's ItemsSource has a binding on Model.CurrentDataTable. If you want to delete a row, you will have to delete the item in that collection. But the DataGrid won't notice that modification, if the collection does not implement INotifyCollectionChanged.
.NET has a builtin ObservableCollection, which implements INotifyCollectionChanged. If you use this collection type for CurrentDataTable, the DataGrid will update itself, when the collection is modified.
WPF Data binding means that you very rarely manipulate the user interface directly. What you're trying to do is directly remove the row from the grid control on the UI, which is how you might have approached things in Winforms.
With WPF data binding the user interface reacts to the underlying data. So in your case the grid is bound onto (or "watching") the contents of the ItemsSource specified by the binding : Binding Model.CurrentDataTable
To delete a row, you need to remove it from the underlying data and the UI will automatically reflect the change.
This is what ObservableCollection and INotifyPropertyChanged are all about - you really need to read up on them if you're doing WPF development!
Related
I'm learning WPF and am really trying to drill down on binding until I can do it like a boss. But I'm having a bit of an issue.
In xaml, I have a ListBox like so:
<ListBox Name="AccountsDisplay"
SelectedValuePath="Username"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Accounts}"
/>
And I have a TextBox that's pulling "Username" from said ListBox.
<TextBox Text="{Binding ElementName=AccountsDisplay, Path=SelectedValue}"/>
Note: Accounts is both an ObservableCollection and all objects added to it are of type Account, which is purely a data class that extends INotifyPropertyChanged, and has properties such as Username, Password, etc.
The TextBox is pulling the Username property properly, and updates any time I change selection in the ListBox (which is populated with pretty lil' Account info entries, as intended), but I cannot then click on the TextBox and attempt to update the Username portion of entries in the ListBox.
My gut tells me I'm going about this TextBox the wrong way, since I won't be able to make other TextBoxes and pull any additional Account properties (thanks to SelectedValuePath already having a value), but I'm too new to WPF & XAML to see where the error is in my ways!
Am I barking up the right tree, or is there a more appropriate way to get a TextBox to synchronize with (and edit) the data in another UI Element?
Consider binding to the property of the actual DataContext of the list item selected.
I do not use SelectedValue because I am not sure of it's purpose.
Because of my ignorance regarding the use of that particular property, I just rely on SelectedItem.
I can then specify the property name that I want to bind to relative to the DataContext of the selected list item.
<TextBox Text="{Binding ElementName=AccountsDisplay, Path=SelectedItem.Username}"/>
I have a WPF Data Grid bound to an observable collection, which is working as intended.
What I am trying to do now is add text below it to say: "Number of selected rows: {count goes here}"
What's the proper way to do this? I could add a new property in the View Model called SelectedCount or something similar and bind to that, but it doesn't feel right. It seems redundant. Also, I could set the label text dynamically in the code behind, but I'm not sure if that's the "right" place to do this either.
Here's an example below.
EDIT:
Please pretend there's a checkbox column header whose intention is to provide check/uncheck all functionality. The state of this header checkbox should not count towards the final count.
You could use element binding to declaratively bind to the SelectedItems.Count property in XAML:
<TextBlock Text="{Binding ElementName=MyDataGrid,
Path=SelectedItems.Count, StringFormat=Number of selected rows: {0}}" />
Update
Presumably you're using MVVM, so adding a SelectedXCount property to your view model is a perfectly reasonable application of the view model. The advantage of having it in the view model is that you could unit test based on the number of selected items. E.g. if you want to check that the user can only progress (a CanNext property returns true) if the user has selected some items.
The SelectedItems property is not a DependencyProperty so can't be bound to, but there are many articles online that get around the issue when using the DataGrid in MVVM. Most of the solutions involve using a mechanism for calling a view model command on the invocation of the DataGrid's SelectionChanged event.
I am stuck on how to pass data from one control to another. If I have a listbox control and the Contol Item contains a datatemplate which renders out 5 fields ( first name, last name, email, phone and DOB) all of which come from an observable collection. How can I allow the user to select a listbox item and have the valuesbe stored within a new listbox control?
Is this done through the creation of a new collection or is there a more simple way to bind these values to a new control?
thank you,
If it is not too late, I would strongly recommend that you use the MVVM pattern. The problem you are facing is typical for WPF without a decent presentation model and wont be the last one.
Using MVVM you would pass data between controls/views through the ViewModel. In your example you would have a PersonViewModel with an ObservableCollection containing first name, last name, email and DOB. Additionally it would have a property SelectedItem. This property can be bound to in a lot of different controls/views without them having to know each other.
Let's say you have a:
<ListBox Name="DemoList" ItemsSource="{Binding ...}">
<ListBox.ItemTemplate>
...
</ListBox.ItemTemplate>
</ListBox>
And another control, maybe a TextBox:
<TextBox Text="I want to bind this to the Email property" />
You can achieve this pretty easily, with:
<TextBox Text="{Binding ElementName=DemoList, Path=SelectedItem.Email}" />
Note the ElementName property of the Binding. This allows you to bind relative to another control, and in this case you want the SelectedItem of your ListBox. SelectedItem will contain an element of the collection in the ItemsSource (or null if nothing is selected), so you can then bind to its properties.
It gets more complex if you want to support multiple selection, but it doesn't sound like this is a requirement for you.
I have a WPF listview, and in one column the cell may contain one or more ListBoxes.
When I right-click a ListBox I'm building a context menu where each item has a DelegateCommand. Currently I'm setting the command parameter to a SelectedListBox property on the page viewmodel itself as my delegate command needs to know which ListBox has been right-clicked.
However this is leading to weird behaviour, which I'm assuming is because I'm binding multiple ListBoxes to the same page-level property (SelectedListBox).
The relevant XAML for the cell template for the listview is as follows:
<DataTemplate x:Key="MultipleListBoxCellTemplate">
<ListBox SelectedItem="{Binding Path=DataContext.SelectedListBox, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Page}}}" />
</DataTemplate>
Is there a better way to get which ListBox has been right-clicked to my viewmodel, or can anyone think of another approach? Much appreciated :)
When you are building the context menu, you know which list box was selected, yes? I would probably wrap that up in the ICommand you are binding the context item to. This way, each command knows exactly which ListBox it was created by and can get the selected item from there.
Alternately, you may be able to get around the issue with using SelectedItem by changing your binding to OneWayToSource so that the data only flows from the View back to the ViewModel. You may still have timing issues, which I suspect is your current problem, but depending on exactly what is going on, that may resolve it.
I am trying to develop a filtering functionality for WPF DataGrid (from the WPF Toolkit). I want a user to right-click any cell and select Filter from its CcontextMenu, and then the grid should be filtered by the cell's value.
I am trying the M-V-VM pattern. My windows's datacontext is MainWindowViewModel which has a property Transactions. This property returns ObservableCollection<TransactionViewModel>, and the data grid uses this collection as its items source. So basically each row is bounded to TransactionViewModel (as you can guess, this grid lists transactions). MainWindowsViewModel has ICollectionView which is used for filtering and tracking the currently selected row. The DataGrid has its property IsSynchronizedWithCurrentItem set to "true", so myCollectionView.CurrentItem gives me the currently selected TransactionViewModel.
The only thing I still need to know is by which column I need to filter. This depends on where the user clicked the context menu. So I am trying to pass this information using CommandProperty of the context menu item. And here I have a real problem. I tried this:
CommandParameter="{Binding Column.Binding.Path.Path,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type tk:DataGridCell}}}" />
This is really ugly, but this works for DataGridTextColumns. Unfortunately, I have also DataGridTemplateColumns, and they don't work (the path is different there, because I need to reach the actual cell template)...
So how can I implement this functionality? Perhaps the whole way is wrong? I didn't find any valuable example on that. The only thing I found is the WPF DataGrid autofilter implementation on the Codeproject which doesn't work at all for some reason...
Thank you.
I'm not 100% sure if this would help but...
DataGrid has CurrentCell so you could bind it in TwoWay mode in your MainWindowViewModel.
Then every "row" could point to DoFilter command defined in MainWindowViewModel. It's not a beauty solution (because viewmodel has to know DataGrid Cell type) but it should work.
Why not just pass the cell as a parameter like this:
CommandParameter=
"{Binding RelativeSource={RelativeSource FindAncestor,tk:DataGridCell,1}}" />
and let your command's Executed event handle all the hard part of finding the actual column name? That way you can write all the special-case code you need.