How to know when binding is completed? - wpf

When I set the .ItemSource() property on a DataGrid to a Collection, the call returns fast, but the actual binding happens afterwards. Since I want to display a waiting cursor, I need to detect when the actual binding has finished. Is there any event for this?

Anything based on ItemsControl uses an ItemContainerGenerator to generate its items in the background. You can access the ItemContainerGenerator property of the DataGrid and hook up the StatusChanged event to determine when it's done. If you're using virtualization and scroll, this will fire again so you need to handle that if necessary in your case.

I waited for my DataGrid's Loaded event to fire, and I did a BeginInvoke, like this:
private void SubjectsList_Loaded(object sender, RoutedEventArgs e)
{
Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() => ColorMyRows()));
}
More details available in my answer here: https://stackoverflow.com/a/44464630/2101117

Your best bet is to hook into OnPropertyChanged event in your Window or User Control. This event is fired every time a property is updated. Then check for the actual property you wish to observe and take action.
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
if ("YOUR_PROPERTY_NAME".Equals(e.Property.ToString()))
{
// Take action
}
base.OnPropertyChanged(e);
}

Related

Is there a possibility to programmatically trigger item action in ListView, like when you dobuleclick on it?

I was searching all over the place but I couldn't find an answer. I need to fire up an ListView item action, so it would rise the ItemActivate event. For now, it's only possible using ENTER key or double click... I would like to know if I could programmatically do that, something like :
listView.Items[int].Activate();
This doesn't work of course, because that function Activate() is not implemented there. For example, I couldn't find how to trigger buttons programmatically, but there it was, in the context menu which appears while you type:
buttonX.PerformClick();
...and it would trigger the button_click event. I wonder if there's something similar in the ListView control for triggering items inside of it ? I want it to raise this event programmatically and not by mouse doubleclick or Enter key on the keyboard...
private void myListView_ItemActivate(object sender, EventArgs e)
{
MessageBox.Show("hello");
}
According to the documentation, the EventHandler in the ListView should be public. So you can raise the event with:
myListView.ItemActivate(myListView, EventArgs.Empty);
This way everyone who subscribed to this event will get notified.
Another way, of course, is to directly call your method:
myListView_ItemActivate(this, EventArgs.Empty);
But this doesn't really classify as "raising the event", because you actually don't raise an event. You just call a method.

How to listen to CollectionChanged event and execute some method

My viewmodel has two Collections, one is MainCollection and other is DerivedCollection. They are displayed using a control, so that when user interacts with the mouse, items can be added or removed from MainCollection, and DerivedCollection should be refreshed accordingly.
The first part (updating MainCollection) happens automatically via data-binding, but I don' know how can I hook RefreshDerivedCollection method to MainCollection.PropertyChanged event.
Both collections and the method live in the same viewmodel.
You can subscribe to MainCollection.CollectionChanged and refresh derived collection there:
MainCollection.CollectionChanged += this.OnMainCollectionChanged;
and
void OnMainCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// TODO: Handle main collection change here.
}

What event is fired when a UserControl is displayed?

I'm trying to add a fade effect (animation) for WPF UserControls (although rather for FrameworkElement, to make it more general).
If I let the Loaded event trigger the initial fade-in, the fade animation will sometimes have started before the UserControl has been displayed. The result is a mess. That happens for example if the UserControl does something lengthy (a few tenths of a second), like execute a query, in the Loaded event handler.
So, I would need to handle some event that FrameworkElement/UserControl gets when the content has been rendered, and start the fade-in then. The System.Windows.Window has a ContentRendered event, but UserControl has not. So, what event is fired when a FrameworkElement (or UserControl) has been rendered?
Try to check size on SizeChanged or LayoutUpdated. Do job when actual width or height not equals to 0.
view.LayoutUpdated+=(o,e)=>
{
if (!loaded && (view.ActualHeight > 0 || view.ActualWidth > 0))
{
// You can also unsubscribe event here.
loaded =true;
}
}
Years late, but since I was looking for working solution since now in vain, I want to share my discovery.
If you want a ContentRendered event for any Control (or any Visual or even DependencyObject), you have to dig down to Visual.
I use this code:
// Wait for Control to Load
void TestUserControl_Loaded(object sender, RoutedEventArgs e)
{
// Get PresentationSource
PresentationSource presentationSource = PresentationSource.FromVisual((Visual)sender);
// Subscribe to PresentationSource's ContentRendered event
presentationSource.ContentRendered += TestUserControl_ContentRendered;
}
void TestUserControl_ContentRendered(object sender, EventArgs e)
{
// Don't forget to unsubscribe from the event
((PresentationSource)sender).ContentRendered -= TestUserControl_ContentRendered;
// ..
}
You have to wait for Control Loaded otherwise PresentationSource.FromVisual() returns null.
Various Dispatcher.BeginInvoke methods didn't work consistently for me. Sometimes firing my rendered event long before the control was actually displayed.
This does work for me every time.
I am aware that I am playing with HwndSource here, which is quite low level and I'm not sure of possible implications. (Maybe somebody more experienced can elaborate.)
You can use IsVisibleChnaged event
Assign event handler
MyUserControl.IsVisibleChanged += ScheduleUserControl_IsVisibleChanged;
In event handler check for if is visible or not.
void _IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue)
{
//Visible
}
else
{
//Not Visible
}
}
You can schedule the beginning of your Storyboard with a lower priority, for example:
Dispatcher.BeginInvoke(BeginStoryboardAction, DispatcherPriority.ContextIdle);
Here's an article that discusses the issues related to using this method:
Build More Responsive Apps With The Dispatcher
Maybe try IsVisibleChanged, haven't used it much myself though.
This event is not raised if the element is not being rendered by the layout system, for reasons other than the value of the IsVisible property. For example, the element might not have an associated visual.
You can use GotFocus Event
<i:Interaction.Triggers>
<i:EventTrigger EventName="GotFocus">
<i:InvokeCommandAction Command="{Binding ContentControlLoadedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>

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.

Event handler that will be called when an item is added in a listbox

Is there an event handler that will be called when an item is added in a listbox in WPF?
Thanks!
The problem is that the INotifyCollectionChanged interface which contains the event handler is explicitly implemented, which means you have to first cast the ItemCollection before the event handler can be used:
public MyWindow()
{
InitializeComponent();
((INotifyCollectionChanged)mListBox.Items).CollectionChanged +=
mListBox_CollectionChanged;
}
private void mListBox_CollectionChanged(object sender,
NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
// scroll the new item into view
mListBox.ScrollIntoView(e.NewItems[0]);
}
}
Ref.
Josh's advice about the observable collection should also be considered.
Take a different approach. Create an ObservableCollection (which does have such an event) and set the ItemsSource of the ListBox to this collection. In other words, in WPF you should think about the problem differently. The control isn't necessarily what is being modified ... the collection behind it is.
UPDATE
Based on your comment to Mitch's answer which indicates your binding source is actually an XML document, I suggest looking into hooking up to the XObject.Changed event of the XML document/element/etc. This will give you change information about the XML structure itself - not the ItemCollection which is an implementation detail you shouldn't need to consider. For example, ItemCollection (or any INotifyCollectionChanged) doesn't guarantee an individual event for every change. As you noted, sometimes you'll just get a generic reset notification.

Resources