-
A few good custom WPF controls found along the way
Posted on January 24th, 2010 3 commentsSo in my work with WPF, I’ve needed either controls to supplement what was missing from Winforms or simply to match up with the current user experience’s of today’s application. I take no credit in actually developing these controls, just finding them on the web via Google. FYI – this article was written on .NET 3.5 as I know some of these will be included with .NET 4.0 WPF.
Linklabel:
http://www.blagoev.com/Blog/post/Building-a-WPF-LinkLabel-control.aspxNOTE: I highly recommend properly binding the IsEnabled property in the Style. If you don’t, having the IsEnabled property set to false on initial load and then changing it later will not properly enable the control.
To be more specific, add the highlighted line in the Template setter:<Hyperlink
x:Name=”PART_InnerHyperlink”
NavigateUri=”{Binding RelativeSource= {RelativeSource TemplatedParent}, Path=Url}”
Style= “{Binding RelativeSource= {RelativeSource TemplatedParent}, Path=HyperlinkStyle}”
Command=”{Binding RelativeSource= {RelativeSource TemplatedParent}, Path=Command}”
CommandParameter=”{Binding RelativeSource= {RelativeSource TemplatedParent}, Path=CommandParameter}”
CommandTarget=”{Binding RelativeSource= {RelativeSource TemplatedParent}, Path=CommandTarget}”
IsEnabled=”{Binding RelativeSource= {RelativeSource TemplatedParent}, Path=IsEnabled}”>
<local:BindableRun
BoundText=”{Binding RelativeSource= {RelativeSource TemplatedParent}, Path=Content}”/>
</Hyperlink>SearchTextBox:
http://davidowens.wordpress.com/2009/02/18/wpf-search-text-box/WPF Datagrid (I’m sure you know about this one):
http://www.codeplex.com/wpfSplitbutton (Couple different flavors here):
http://anothersplitbutton.codeplex.com/
http://www.codeproject.com/KB/WPF/WpfSplitButton.aspx
http://blogs.msdn.com/llobo/archive/2006/10/25/Split-Button-in-WPF.aspx
http://wpfsplitbutton.codeplex.com/Closeable Tab:
http://geekswithblogs.net/kobush/archive/2007/04/08/CloseableTabItem.aspxLoading animation (I find that using the base is fine but making these your own is pretty easy):
http://social.msdn.microsoft.com/forums/en-US/wpf/thread/0875ebf8-bb77-45ea-a929-d40743a3bf03/
http://chriscavanagh.wordpress.com/2008/07/25/improved-xaml-loading-animation/
http://brianlagunas.com/2009/08/21/a-simple-wpf-loading-animation/DockPanelSplitter (added this after the post as I found it the same day, amazingly helpful control):
http://www.codeproject.com/KB/WPF/DockPanelSplitter.aspxFYI – if any of these links are down, please let me know and I’ll either update the link.
UPDATE: Fixed the Linklabel link to actually point to the place it stated. Oops
-
Handling Secondary Thread Exceptions in WPF
Posted on May 26th, 2009 No commentsAs I’m sure you know, if you’ve played around in WPF enough, you’ve realized that the WPF way to catch unhandled exceptions is through the App.xaml with the DispatcherUnhandledException event. What you may not know is that this only catches unhandled exceptions in the WPF application itself. If you have any threads that throw exceptions or especially secondary threads (created by threads) that throw exceptions, you can kiss your pretty little “catch-all” event bye because your app with crash into the fiery pits of Windows system event log hell.
Recently on a project I’ve been involved with, we’ve been seeing this issue pop up a few times and without any knowledge from the event log, we really had a tough time finding the source of the errors. Enter the throwback to .NET 2.0, CurrentDomain’s UnhandledException event. Our old little pal is back from the past to make an appearance in our pretty little WPF app and, lo and behold, we are able to catch those nasty unhandled exceptions in our secondary threads and perform a more graceful shut down. Very nice and very clean all with a simple code block:
private void Application_Startup(object sender, StartupEventArgs e) { AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); } void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { //Oh noes! An error occurred! }Now to actually fix the source of the errors!
NOTE: For added fun, if you fancy the use of legacyUnhandledExceptionPolicy, this gets event better.
-
Update to previous mystery WPF issue
Posted on May 6th, 2009 No commentsJust wanted to make it obvious that I’ve updated the previous post about the mystery WPF issue regarding a strange crash. I wouldn’t really call it a solution… more of a workaround for our systems. Let’s hope it holds up in the long run (or at least until this issue is addressed by Microsoft, which probably won’t happen anytime soon since they haven’t responded to any requests).
-
Mystery WPF problem that I need help with…
Posted on April 20th, 2009 1 commentI didn’t want to do this so early in the life of this site but I’m at a loss of what to do. We’ve got a heavy WPF application which has a nice little animated progress spinner on it using WPF animation (DoubleAnimation). The problem is basically laid out here: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/a4b2df90-8fa3-4b59-9242-9c48000fa62a. As you can see, there’s no answers yet and it’s been out there since March. We are seeing this randomly occur in our application and I have identified the source POSSIBLY being the progress spinner’s infinite animation (we turned the animation off and don’t see the problem again… yet).
Here’s our stacktrace. As you can see there, is not specific source to OUR code… it’s all WPF internals… and this happens completely randomly at random intervals and is not reproduceable on some machines. I appreciate any help that can be provided.
===================================
Unhandled exception detected in application. Please see technical details for more information: UIElement.Measure(availableSize) cannot be called with NaN size.
===================================
UIElement.Measure(availableSize) cannot be called with NaN size. (PresentationCore)
——————————
Program Location:
at System.Windows.UIElement.Measure(Size availableSize)
at MS.Internal.Helper.MeasureElementWithSingleChild(UIElement element, Size constraint)
at System.Windows.Controls.ItemsPresenter.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at MS.Internal.Helper.MeasureElementWithSingleChild(UIElement element, Size constraint)
at System.Windows.Controls.ScrollContentPresenter.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Grid.MeasureCell(Int32 cell, Boolean forceInfinityV)
at System.Windows.Controls.Grid.MeasureCellsGroup(Int32 cellsHead, Size referenceSize, Boolean ignoreDesiredSizeU, Boolean forceInfinityV)
at System.Windows.Controls.Grid.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.ScrollViewer.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Border.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Control.MeasureOverride(Size constraint)
at Microsoft.Windows.Controls.DataGrid.MeasureOverride(Size availableSize)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.DockPanel.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at MS.Internal.Helper.MeasureElementWithSingleChild(UIElement element, Size constraint)
at System.Windows.Controls.ContentPresenter.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Grid.MeasureCell(Int32 cell, Boolean forceInfinityV)
at System.Windows.Controls.Grid.MeasureCellsGroup(Int32 cellsHead, Size referenceSize, Boolean ignoreDesiredSizeU, Boolean forceInfinityV)
at System.Windows.Controls.Grid.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Control.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Grid.MeasureCell(Int32 cell, Boolean forceInfinityV)
at System.Windows.Controls.Grid.MeasureCellsGroup(Int32 cellsHead, Size referenceSize, Boolean ignoreDesiredSizeU, Boolean forceInfinityV)
at System.Windows.Controls.Grid.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at MS.Internal.Helper.MeasureElementWithSingleChild(UIElement element, Size constraint)
at System.Windows.Controls.ContentPresenter.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Grid.MeasureCell(Int32 cell, Boolean forceInfinityV)
at System.Windows.Controls.Grid.MeasureCellsGroup(Int32 cellsHead, Size referenceSize, Boolean ignoreDesiredSizeU, Boolean forceInfinityV)
at System.Windows.Controls.Grid.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Control.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.DockPanel.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at MS.Internal.Helper.MeasureElementWithSingleChild(UIElement element, Size constraint)
at System.Windows.Controls.ContentPresenter.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Border.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Page.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at MS.Internal.Helper.MeasureElementWithSingleChild(UIElement element, Size constraint)
at System.Windows.Controls.ContentPresenter.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.ContextLayoutManager.UpdateLayout()
at System.Windows.ContextLayoutManager.UpdateLayoutCallback(Object arg)
at System.Windows.Media.MediaContext.InvokeOnRenderCallback.DoWork()
at System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()
at System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget)
at System.Windows.Media.MediaContext.RenderMessageHandler(Object resizedCompositionTarget)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
EDIT: Grrr.. even with the animations off, there’s still a problem. Here’s a new stacktrace:
===================================Unhandled exception detected in application. Please see technical details for more information: TimeSpan does not accept floating point Not-a-Number values.
===================================
TimeSpan does not accept floating point Not-a-Number values. (mscorlib)
——————————
Program Location:at System.TimeSpan.Interval(Double value, Int32 scale)
at System.Windows.Media.MediaContext.ScheduleNextRenderOp(TimeSpan minimumDelay)
at System.Windows.Media.MediaContext.EstimatedNextVSyncTimeExpired(Object sender, EventArgs e)
at System.Windows.Threading.DispatcherTimer.FireTick(Object unused)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)EDIT: Just wanted to update everyone on how we minimized this issue. From the MSDN forums, the only common link we could find is our development machine hardware/software. The only conclusion we could come up with is a WPF incompatibility between our hardware and/or software. We added an app settings flag that is checked before any infinite animations are executed and that flag is set to true to disable the animations on our development machines but set to false during deployment. This gives us access to enable/disable this feature if we ever see it occur on client computers (which we hope does not happen!).
-
Quick way to lower CPU usage in heavy WPF animation desktop app
Posted on April 17th, 2009 1 commentEarlier this week, we ran into an issue where our desktop application (WPF heavy) was attacking our CPU cycles. Upon further investigation, all problems pointed to our lovely progress spinning controls which are powered by looping WPF animations. After some dabbling with replacing the animations with animated GIFs turned out to be more than its worth (and still gobbled a few cycles), we decided to go with a lovely suggestion from the MSDN forums about reducing the frames per second on the WPF animations update.
The result was this simple little piece of code:
Timeline.DesiredFrameRateProperty.OverrideMetadata(typeof(Timeline), new FrameworkPropertyMetadata { DefaultValue = 20 });A small reduction in the visual refresh rate down to 20 FPS (not easily noticeable to the user) resulted in a huge decrease in CPU usage… from over an average of 30% CPU usage down to an average of 5%.
On a separate note… word to the wise, don’t bind properties directly to UI elements in WPF which internally make database calls… even if you load the items asynchronously, WPF will bind and make the DB calls on the main thread which will block the UI.
-
Virtualized WPF Listbox scrolling (because ScrollIntoView doesn’t always work)
Posted on April 16th, 2009 3 commentsI guess I’ll start this off the fun way… with a recent issue I was involved with yesterday regarding a rogue list box. So to explain the issue, I’ve got a virtualized list box full of nice little custom objects. The user has access to delete these items from said listbox. The problem comes into play where, if the user has scrolled down the listbox but then deletes the items they are looking at and the scroll bar disappears (it will disappear if the number of items in the listbox is less than the amount that needs a scrollbar), the user can no longer scroll to the top of the listbox. So the items will be inaccessible!
After spending a little time Googling and realizing that ListBox’s ScrollIntoView did nothing, I found an excellent forum post that detailed the notion of directly accessing the scrollviewer inside the listbox Once I had access to that, I could scroll all I wanted to.
I basically just added this function:
private childItem FindVisualChild<childItem>(DependencyObject obj) where childItem : DependencyObject { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) { DependencyObject child = VisualTreeHelper.GetChild(obj, i); if (child != null && child is childItem) { return (childItem)child; } else { childItem childOfChild = FindVisualChild<childItem>(child); if (childOfChild != null) { return childOfChild; } } } return null; }Adding a call to it to walk the visual tree for the scrollviewer:
ScrollViewer sv = FindVisualChild<ScrollViewer>(uxListBox);
And that’s it! Now I can sv.ScrollToTop(), ScrollToBottom(), or even specific vertical/horizontal offsets. I do have to make a call to ListBox.UpdateLayout() to refresh but it’s all good now… crisis #93487 averted!
Thanks to this post for guiding me to the light!

