Force rebind on a WPF control or view by resetting the DataContext without using null!

I had an issue where I wanted to force a datacontext to rebind everything. The RaisePropertyChanged(“”) wasn’t working and I like to keep things simple.

I was setting the DataContext = null then setting it back to the desired object right after to force a rebind. This worked well but really pissed off some of the controls. Not everyone appreciates a null databind.

So, what to do. I remember working with virtualization and the DisconnectedItem, a hidden magical gem that Microsoft just finally let us have public access to in 4.5, had magical powers with databinding. It cast a spell that made everyone calm and happy.

The null databinding on the DataContext was causing major slowdowns in the app as all the controls got angry. So I switched the DataContext=null to DataContext = DisconnectedItem.

All was right in the world again and the application became fast again.

Confused, well I am tired. Anyway, here it is in the before and after and it should then make sense. Edited for brevity.

private static object disconnectedItem = null;
 
        private void UpdatePropertiesView()
        {                   
                    newView.DataContext = null;
                    newView.DataContext = SelectedNode.Node;                               
        }

Snippet

private static object disconnectedItem = null;
 
        private void UpdatePropertiesView()
        {
                    if (disconnectedItem == null)
                        disconnectedItem = typeof(System.Windows.Data.BindingExpressionBase).GetField("DisconnectedItem", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null);
                    newView.DataContext = disconnectedItem;//force rebind, but gentler.
                    newView.DataContext = SelectedNode.Node;                               
            }
        }

 

The reason I am doing this is because the Node object didn’t change, but the properties on it did.(a lot of them).

Happy Coding!

PS: Yes, I am adding a check to see if the datacontext is the same so I can skip the null set entirely in those instances…..

 

 

System.InvalidOperationException with RadRichTextbox from Telerik in WPF

If you have an HTML document that you import into the RadRichTextbox that has images and you are hosting WPF within MFC (c++), then you are probably running into this issue. Right along with all the people who have a steering wheel on the right side of the car driving around in the States. Yeah, all 1 of us.

Anyway, it’s an issue for us but here is the work around since Telerik will probably be slow to fix it, if they do. Quick backstory, they  load the images using WebClient instead of loading from disk. Better yet, they use the async methods on the webclient with a callback. We all know how much WPF loves stuff from other threads.

Here is the fix.

Snippet

  {//.........some function some where in time.
  var formatter = new HtmlFormatProvider();//The thing you use to load your html
    formatter.ImportSettings.LoadImageFromUrl += ImportSettings_LoadImageFromUrl;
    var doc = formatter.Import(html);//html is your variable with your html....from whereever
    boxxy.Document = doc;//boxxy is my richtextbox instance
}
 //the meat and potato's 
void ImportSettings_LoadImageFromUrl(object sender, LoadImageEventArgs e)
{           
    using (var file = new FileStream(e.Url, FileMode.Open))
    {
        e.ImageElement.UriSource = null;//prevent them from trying to load in background
        e.ImageElement.Init(file, Path.GetExtension(e.Url));//load from our stream
        e.ImageElement.ImageSource.Freeze();//prevent cross thread issue by freezing it.
    }
    e.Handled = true;
}

 

Happy Coding!

The type initializer for +’System.Windows.PresentationSource’ threw an exception.

I had an issue with a 3rd party control. I couldn’t blame them too much since the issue only happened in the WPF control hosted in a MFC C++ application. brutal for sure.

Why host WPF in C++? That is a question for another time, but let’s just say its an app written in the early 90’s and still has been rewritten, just bolted on and refactored.

Well, I created the test application and it worked great on my machine at home. I loaded it into my work computer and blammo, it threw up on the get handle call. WTF?

If you step into the .NET source(slow but very helpful), you get this.

System.Runtime.Versioning.BinaryCompatibility.ParseTargetFrameworkMonikerIn/toEnum in the call stack. and  NULL parameter exception.

Turns out through some goofiness in VC++, it will insert a null value in a manifest.

The fix is really easy. Delete all the files in your AppData\Local\Temp folder under your profile.

Here is a link to a guy who wrote about it in much more detail, but man that was non-intuitive fix. It worked though, so I am happy!

Thanks Microsoft for stealing another hour of my life. Thanks Telerik for being there to steal a week trying to reproduce bugs in your silly slow controls.

Happy coding!

 

How to display a different value in a WPF combobox based on selection

I couldn’t figure out a great way to title this post. Anyway, the issue I had was having a (none) value in the combobox but when it is selected show a blank combo. Those were the requirements and I wanted to do an easy solution without having to write a converter. Here is the solution using a simple style. Note, the StringResources line is where the source of the (none)string lives, You could just hard code this to your string if you aren’t pulling from a resource file.

Snippet

    <!-- Style for a combobox so that if the none value is picked, it will show up as a blank string.-->
    <Style TargetType="ComboBox" BasedOn="{StaticResource {x:Type ComboBox}}">
        <Setter Property="Foreground" Value="DarkBlue"/>
        <Setter Property="Margin" Value="0,2,0,2"/>
        <Setter Property="ItemTemplate">
            <Setter.Value>
                <DataTemplate>
                    <TextBlock Margin="0">
                        <TextBlock.Style>
                            <Style TargetType="TextBlock">
                                <Style.Setters>
                                    <Setter Property="Text" Value="{Binding}"/>
                                </Style.Setters>
                                <Style.Triggers>
                                    <MultiDataTrigger><!-- handle the display struct-->
                                        <MultiDataTrigger.Conditions>
                                            <Condition Binding="{Binding RelativeSource={RelativeSource AncestorType=ComboBoxItem},FallbackValue={x:Null}}" Value="{x:Null}"/>
                                            <Condition Binding="{Binding Text}" Value="{x:Static StringResources:WorkProgram.NoneValue}"/>
                                        </MultiDataTrigger.Conditions>
                                        <MultiDataTrigger.Setters>
                                            <Setter Property="Text" Value=" "/>
                                        </MultiDataTrigger.Setters>                                        
                                    </MultiDataTrigger>                                  
                                </Style.Triggers>
                            </Style>
                        </TextBlock.Style>
                    </TextBlock>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Hapy coding!

FIX: TabControl in WPF Shows wrong tab if Active Tab is Invisible

You want to dynamically show or hide tabs in WPF. Say, some only show up if a certain option is set. Well, it shows anyway if its the first tab. Stupid. Here is an attached property to fix that.

Based on code from http://www.codeproject.com/Articles/349140/WPF-TabControl-focus-behavior-with-invisible-tabs

 

using System;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
namespace Seekford
{/// <summary>Behaviors for TabControl.
    /// </summary>
    public class TabControlBehavior
    {
        /// <summary>Whether to focus the first visible tab.
        /// </summary>
        /// <remarks>Setting the FocusFirstVisibleTab
        /// attached property to true will focus the next visible tab when
        /// the current selected tab's Visibility property is set to Collapsed or Hidden.</remarks>
        public static readonly DependencyProperty FocusFirstVisibleTabProperty =
            DependencyProperty.RegisterAttached("FocusFirstVisibleTab", typeof(bool),
                typeof(TabControlBehavior),
                new FrameworkPropertyMetadata(OnFocusFirstVisibleTabPropertyChanged));
        /// <summary>Gets the focus first visible tab value of the given element.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        public static bool GetFocusFirstVisibleTab(TabControl element)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }
            return (bool)element.GetValue(FocusFirstVisibleTabProperty);
        }
        /// <summary>Sets the focus first visible tab value of the given element.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="value">if set to <c>true</c> [value].</param>
        public static void SetFocusFirstVisibleTab(TabControl element, bool value)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }
            element.SetValue(FocusFirstVisibleTabProperty, value);
        }
        /// <summary>Determines whether the value of the dependency property <c>IsFocused</c> has change.
        /// </summary>
        /// <param name="d">The dependency object.</param>
        /// <param name="e">The  instance containing the event data.</param>
        private static void OnFocusFirstVisibleTabPropertyChanged(
                DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var tabControl = d as TabControl;
            if (tabControl != null)
            {
                // Attach or detach the event handlers.
                tabControl.IsSynchronizedWithCurrentItem = true;
                if ((bool)e.NewValue)
                {
                    var collection = tabControl.Items as INotifyCollectionChanged;
                    if (collection != null)
                    {
                        collection.CollectionChanged +=
                          new NotifyCollectionChangedEventHandler(TabControl_Items_CollectionChanged);
                    }
                }
                else
                {
                    // Disable the attached behavior.
                    var collection = tabControl.Items as INotifyCollectionChanged;
                    if (collection != null)
                    {
                        collection.CollectionChanged -=
                          new NotifyCollectionChangedEventHandler(TabControl_Items_CollectionChanged);
                    }
                    // Detach handlers from the tab items.
                    foreach (var item in tabControl.Items)
                    {
                        TabItem tab = item as TabItem;
                        if (tab != null)
                        {
                            tab.IsVisibleChanged -=
                              new DependencyPropertyChangedEventHandler(TabItem_IsVisibleChanged);
                        }
                    }
                }
            }
        }
        /// <summary>Handles the CollectionChanged event of the TabControl.Items collection.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see
        ///    cref="System.Collections.Specialized.NotifyCollectionChangedEventArgs"/>
        ///    instance containing the event data.</param>
        static void TabControl_Items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            // Attach event handlers to each tab so that when the Visibility property changes of the selected tab,
            // the focus can be shifted to the next (or previous, if not next tab available) tab.
            var collection = sender as ItemCollection;
            if (collection != null)
            {
                switch (e.Action)
                {
                    case NotifyCollectionChangedAction.Add:
                    case NotifyCollectionChangedAction.Remove:
                    case NotifyCollectionChangedAction.Replace:
                        // Attach event handlers to the Visibility and IsEnabled properties.
                        if (e.NewItems != null)
                        {
                            foreach (var item in e.NewItems)
                            {
                                TabItem tab = item as TabItem;
                                if (tab != null)
                                {
                                    tab.IsVisibleChanged +=
                                      new DependencyPropertyChangedEventHandler(TabItem_IsVisibleChanged);
                                }
                            }
                        }
                        // Detach event handlers from old items.
                        if (e.OldItems != null)
                        {
                            foreach (var item in e.OldItems)
                            {
                                TabItem tab = item as TabItem;
                                if (tab != null)
                                {
                                    tab.IsVisibleChanged -=
                                      new DependencyPropertyChangedEventHandler(TabItem_IsVisibleChanged);
                                }
                            }
                        }
                        break;
                    case NotifyCollectionChangedAction.Reset:
                        // Attach event handlers to the Visibility and IsEnabled properties.
                        foreach (var item in collection)
                        {
                            TabItem tab = item as TabItem;
                            if (tab != null)
                            {
                                tab.IsVisibleChanged +=
                                  new DependencyPropertyChangedEventHandler(TabItem_IsVisibleChanged);
                            }
                        }
                        break;
                    case NotifyCollectionChangedAction.Move:
                    default:
                        break;
                }
                // Select the first element if necessary.
                if (collection.Count > 0 && collection.CurrentItem == null)
                {
                    foreach (var item in collection)
                    {
                        if ((item as TabItem).Visibility == Visibility.Visible)
                        {
                            collection.MoveCurrentTo(item);
                            break;
                        }
                    }
                }
            }
        }
        /// <summary>Handles the IsVisibleChanged event of the tab item.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see
        ///   cref="System.Windows.DependencyPropertyChangedEventArgs"/>
        ///   instance containing the event data.</param>
        static void TabItem_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            TabItem tab = sender as TabItem;
            if (tab != null)
            {
                //ensure active tab is visible
                TabControl tabControl = tab.Parent as TabControl;
                if (tabControl != null)
                {
                    bool goforward = true;
                    while (tabControl.SelectedItem == null || (!(tabControl.SelectedItem as TabItem).IsVisible))
                    {
                        if (goforward)
                        {
                            goforward = tabControl.Items.MoveCurrentToNext();
                        }
                        else
                        {
                            if (!tabControl.Items.MoveCurrentToPrevious())
                                break;//nothing is visible
                        }
                    }
                }
            }
        }
    }
}

 

Happy Coding

How to center or right align the Header in the WPF RadGridView by Telerik?

Telerik is not the best at providing documentation on how to do things, so I figured I would write some of the more mundane tasks that took me a few minutes thought.

Here, I needed to center my headers. It is easy but only if you know all the magic words. If you don’t, it is pretty hard.

Here is how you do it. A simple style.

Snippet

        <telerik:RadTreeListView ItemsSource="{Binding Nodes}" AutoGenerateColumns="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                               IsExpandedBinding="{Binding IsExpanded,Mode=TwoWay}"                                 
                               Name="mainTree"
                               SelectionUnit="FullRow"                                 
                               RowIndicatorVisibility="Collapsed"
                               CanUserResizeColumns="False"
                             SelectedItem="{Binding SelectedNode,Mode=TwoWay}"
                               >
            <telerik:RadTreeListView.Resources>
                <Style BasedOn="{StaticResource {x:Type telerik:GridViewHeaderCell}}" TargetType="{x:Type  telerik:GridViewHeaderCell}">
                    <Setter Property="HorizontalContentAlignment" Value="Center"/>
                </Style>
            </telerik:RadTreeListView.Resources>
......

Happy Coding!

WPF Validation Errors not showing on initial load of control or window

I was setting validation errors on the initial load of my view model, and to my annoyance the window would show up like everything was great. The validation code was definitely running, the HasErrors was true, the dictionaries were filled with the errors but the form was like, “What errors?”  This irritated me. Well, WPF is stupid in this regard and doesn’t handle things properly. If you are like me, you set your datacontext after creating the view. Well, that is the logical way, but if you want validation you need to slightly alter that. I found a work around that fixes the problem, but is a little more annoying. Simply put, pass in your VM to the constructor of the view. Cache that, then set your DataContext(DC) on the load event. Sample code below:

public partial class AcceptRejectViewOldMeetsNew : UserControl
 {
   private object dcToSet = null;
   public AcceptRejectViewOldMeetsNew(object dc)
  {
    InitializeComponent();
    dcToSet = dc;
    this.Loaded += AcceptRejectViewOldMeetsNew_Loaded;
  }
  void AcceptRejectViewOldMeetsNew_Loaded(object sender, System.Windows.RoutedEventArgs e)
  {
    DataContext = dcToSet;
    }
 }

Happy Coding!

Speed up WPF XAML Editor in Visual Studio 2012

Tired of the stupid XAML editor being so slow. Mine freezes, locks up and is otherwise unruly. I didn’t seem to have a choice if I wanted intellisense in Visual Studio before 2012. Well, apparently they fixed the source code editor in 2012 to have working intellisense so there is now a viable option for ditching the buggy standard designer view.

Yes, even if you are in the XAML tab full screen, the stupid designer is still working and crunching on everything you type and blowing its lid at all your inflight incorrect changes.

How do you fix it, easy. Right click your xaml file in the Solution Explorer(filename, not the file contents) and choose Open With…. Pick Source Code Editor. Click the use as default option. Hit ok.

Done. Enjoy not wanting to throw your computer after losing your changes repeatedly due to the designer full on crashing.

Happy Coding!

Want pictures, its the last section of this guys entry. Good reading. The first two were what I had used before since the third wasn’t viable before 2012.

http://blog.spinthemoose.com/2013/03/24/disable-the-xaml-designer-in-visual-studio/

How to handle action on enter key press in textbox in WPF

Did you want your OK button or your commit action to take place when you hit enter in a text field in a WPF dialog? You may have implemented a Find dialog, or maybe you have a one field text entry and you want the Enter key to commit the action.

Well, its actually really easy once you learn the simple trick to wiring up the commands.

I have a command called SaveProcessCommand on my viewmodel. I have it wired to my dialogs “OK” button. I also wanted the user to just hit Enter when they were done typing, since that is how my usability study determined users expect.

Enter the simple InputBinding. Pretty cool.

[csharp] <TextBox Margin="10,0,0,0" HorizontalAlignment="Stretch" Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Grid.Column="1">
<TextBox.InputBindings>
<KeyBinding Command="{Binding SaveProcessCommand}" Key="Enter"/>
</TextBox.InputBindings>
</TextBox>
[/csharp]

I have the binding to the property update on each keystroke, so it is always up to date. The InputBinding then wires up the Enter key to a command. The command can do whatever you want, you are using MVVM right? Happy Coding!

How to reclassify your project into a WPF project in Visual Studio

How to change project type to wpf class library in Visual Studio 2012.

Are you looking to change your project from a normal C# class library to a Window Presentation Framework project?

Well, it is not that hard once you learn the trick. It took me a little while to dig up the info, so hopefully this saves you some time.

Open your csproj file in notepad. Look for the ProjectTypeGuids key. If not found, add it.

Here is what it should look like when your done.

<ProjectTypeGuids>{60DC8134-EBA5-43B8-BCC9-BB4BC16C2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>

Visual Studio 2012 and Visual Studio 2010 use these to identify the project type. The settings above make it a C# WPF app.

Example:

SNAGHTML77868191

 

Happy Coding!