WPF DataGrid how to get when ItemsSource updates - wpf

Which event fires when DataGrid's source is updating? I've tried DataContextChanged and SourceUpdated but it never worked out.
Actually I need a simple thing. I want, if there is a new row comes, scroll the GridView's scrollbar down to the bottom to see what it was.

I had the same problem and I manage it this way
DataGrid myGrid = new DataGrid();
CollectionView myCollectionView = (CollectionView)CollectionViewSource.GetDefaultView(myGrid.Items);
((INotifyCollectionChanged)myCollectionView).CollectionChanged += new NotifyCollectionChangedEventHandler(DataGrid_CollectionChanged);
You then need to implement the logic in the event handler DataGrid_CollectionChanged.

Set NotifyOnTargetUpdated = true for the ItemsSource binding and handle TargetUpdated event. If you've multiple bindings, then look for DataTransferEventArgs Property to find out if the target is ItemsSource or not.

If you are trying to have the grid refresh when something is added to the database itself, that's not going to happen. I'm more familiar with WinForms than WPF but I'm assuming there is no magical way to keep a grid in sync with the database without writing some background process that continuously checks for database changes.
If you are updating the actual data source of the grid (ex. Collection) then that will update the grid.

For my part i've used SelectionChange notification which raise each event Del/Add/Edit/Select
It's work very well
private void dataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Console.WriteLine("hi");
}

Related

DataGrid SelectedIndex Changed Event Handler

I have a WPF DataGrid which I'm trying to auto-scroll using this code:
private void mydatagrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
mydatagrid.ScrollIntoView(mydatagrid.CurrentItem);
}
The problem I'm having is that this event handler is not called every time the SelectedIndex of the DataGrid changes. Yes, it does get called when I click on the grid or add or delete an item, but it does NOT get called upon some other actions, such as moving the currently selected item up or down in the underlying collection, which is set via:
mydatagrid.ItemsSource = Seq;
(where Seq is an object of a type derived from ObservableCollection<>).
In my troubleshooting attempts I bound the text of a TextBlock to the SelectedIndex property of mydatagrid. The index number updates perfectly, regardless of what action I perform on the datagrid and/or underlying data source.
So my question is: how can I create an event handler in C# code that gets called upon ANY and ALL changes to the value of SelectedIndex, just like my little textblock binding example does?
I've tried finding a propertyChanged event for the DataGrid, but to no avail. I've tried tapping into all of the events of the DataGrid that seemed remotely related, but to no avail. I've also tried using the CollectionChanged event of the underlying collection, but this doesn't seem to be nicely synchronized with the datagrid (at least at the moment that the event occurs).
Thanks

Event firing before databinding is updated - how do I wait for the update?

I'm currently encountering this issue while programming Metro, but I'm sure it applies to WPF, Silverlight and possibly even WinForms.
I have a databound TextBox and a method attached to the LostFocus event of the TextBox. When it loses focus, I want the code behind to trigger a save function in order to persist the data. The problem is that the LostFocus-event triggers before the business object is updated from the GUI through TwoWay databinding.
What is the best way to handle this? Is there some way to force update of the databinding from the LostFocus method (would probably be platform-specific)?
It sounds like you're wanting to do some business logic instead of having the GUI update the textbox. I would set the Textbox to only be BindingMode.OneWay, so that when the business object is changed the textbox is updated properly.
Then in the Lostfocus event (again wpf, but I think you'll get the idea):
private void EditBoxLostFocus( object sender, KeyboardFocusChangedEventArgs e )
{
var textbox = sender as TextBox;
//update your business object w/ textbox.Text value
//other business logic
}
This way you're in full control of when the object gets updated, and can apply your business rules.
Set UpdateSourceTrigger = PropertyChanged on the TextBox binding.
http://msdn.microsoft.com/en-us/library/system.windows.data.updatesourcetrigger(v=vs.100).aspx

WPF TextBox lostfocus as attached property

I have a Grid with many TextBoxes and I want to call NotifyPropertyChanged() method to update some other controls everytime one of these TextBox-es changed the value = lost the focus (I don't want to use PropertyChanged as UpdateSourceTrigger)
This is what I can do:
<Grid TextBoxBase.TextChanged="My_TextChanged" >
...
</Grid>
I need something like:
TextBoxBase.OnLostFocus
Use the lost focus event
TextBox.LostFocus="OnTextBoxLostFocus"
Filter on textboxes ;)
private void OnTextBoxLostFocus(object sender, RoutedEventArgs e)
{
if(!(e.OriginalSource is TextBox))
return;
//Do stuff
}
If your properties are not changed, your Textboxes will not be updated however. You should consider mutating the data those other TextBoxes are bound to, instead of using LostFocus to update your model.
Good luck!
TextBoxBase.LostFocus is, I suspect, the event you're looking for.
It's listed here: http://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.textboxbase_events.aspx - but it's defined on UIElement - so you possibly want to try UIElement.LostFocus if the above doesn't work in markup.

Silverlight DataBinding Loading Animation

Is there an event somewhere in the Silverlight control model that is raised once an item is databound? I am binding at design time to a large amount of data and would like to display an animation until the databinding is complete.
There is no specific event that is fired when databinding is completed. Your best bet would probably be to key off of the FrameworkElement.LayoutUpdated event. This is the last event in the lifecycle before a control is ready for user interaction. However, this event will continue to be raised many more times due to property changes, size changes, and explicit calls to UpdateLayout() or InvalidateArrange(). Therefore you will have to add some extra logic to make sure that the LayoutUpdated event warrants stopping/hiding your animation, such as only doing it the first time or if you are sure the event was fired due to a change in databinding.
If the control is actually your own custom control and you are binding to custom DependencyProperties on that control then you could raise your own event on the PropertyChangedCallbacks for each of the properties to signal that they have been updated via databinding.
Here's what I do:
private object lastDataContext;
private void MyClass_Loaded(object sender, RoutedEventArgs e)
{
if (DataContext != lastDataContext)
{
perform_onetime_operation();
lastDataContext = DataContext;
}
}
That way perform_onetime_operation will get called not just the first time databinding happens, but any time that the DataContext changes meaning that data is re-bound.

Maintain scroll position on updating the ItemSource of a silverlight datagrid

I'm using a DataGrid in my silverlight application to display some data that's refreshed on a timer. My problem is that when this happens the vertical scrollbar in the grid resets to the top, whereas I want it to stay in the same position. Does anyone know how I can make this happen?
I've tried overriding the ItemsSource property on the grid to store the vertical scroll position and then reset it, but this only affects the scrollbar and doesn't force the correct rows to be displayed. Is there a way to force this behaviour?
Here is a similar question about Setting the scroll bar position on a ListBox
After rebinding Silverlight Listbox control how do you get it listbox to scroll to back to the top?
Since the DataGrid also supports a ScrollIntoView method, you should be able to use a similar technique such as
theDataGrid.ItemsSource = data;
theDataGrid.UpdateLayout();
theDataGrid.ScrollIntoView(theDataGrid.SelectedItem, theDataGrid.Columns[0]);
I couldn't find a decent answer last time I looked. I wanted to keep the current element selected in the grid but that wouldn't work on an ICollectionView refresh (I use MVVM and get automatic updates from the server).
ScrollIntoView() was not an option for me because the currently selected item may NOT be in view. Having the CurrentChanged event firing out of control was also quite a bother.
In the end, I used the Infragistics grid and it does just that out of the box. Problem solved for me.
You may have a look at the DevExpress free grid. I think it had the same nice behaviour (I tested it but I can't remember the outcome).
You could try setting the SelectedItem thro the UI thread, so that the UI can refresh itself,
like so
private void Button_Click(object sender, RoutedEventArgs e)
{
Person p = new Person() { Name="sss",Age=11}; //datagird's itemsSource is Collection<person>
people.Add(p);
dg.SelectedItem = p; //dg is my datagrid name
Dispatcher.BeginInvoke(() => { dg.SelectedItem = p; });
}
Im assuming that new rows are loaded thro the ViewModel, so thats why it makes sense to place the BeginInvoke there. Since the ViewModel operations run on a different thread, and just setting the SelectedItem on its own might not work, this has worked for someone else
I've also had issues with this. I solved it by remembering the item I want to scroll to, then re-binding the DataGrid. I handle the LayoutUpdated event in order to implement the desired functionality:
void MyDataGrid_LayoutUpdated(object sender, EventArgs e)
{
// Reference the data item in the list you want to scroll to.
object dataItem = yourDataItem;
// Make sure the item is not null and didn't already scroll to the item.
if (dataItem != null && this.dataItemScrolledTo != dataItem)
{
// Remember the item scrolled to.
this.dataItemScrolledTo = dataItem;
// Scroll datagrid to the desired item.
MyDataGrid.ScrollIntoView(dataItem, MyDataGrid.Columns[0]);
}
}
I've modified CodeMaster's solution so that you don't need a class level variable. Put this code in the method that updates the ItemsSource. It will dynamically create the eventhandler, attach it, then detach it.
EventHandler MyDataGrid_LayoutUpdated = null;
MyDataGrid_LayoutUpdated = (s, e) =>
{
MyDataGrid.ScrollIntoView(dataItem, MyDataGrid.Columns[0]);
MyDataGrid.LayoutUpdated -= MyDataGrid_LayoutUpdated;
};
MyDataGrid.LayoutUpdated += MyDataGrid_LayoutUpdated;

Resources