Saturday, August 22, 2015

RadWindow cause RadComboBox to open popup unexpectedly and workaround

RadWindow and RadComboBox that I am talking about here  are both from Telerik(www.telerik.com) Silverlight controls, we use it quite a lot in our project.

Recently , I notice an issue  when using RadComboBox inside RadWindow , which somehow cause the RadComboBox to open it's dropdown  unexpectedly. Obviously it is quite annoying.

Originally I was suspect it is caused by our program related to the way how we use RadWindow and RadComboBox, but it turns out it is not ,because I created an isolated project and I can reproduce the same issue.  Just create a UserControl, and then drop a few RadComboBox in it.  Set the IsEditable=True, OpenDropDownOnFocus = true.


Then use code to open a RadWindow, Let's call it window1, and set the UserControl we created above as the content.  Inside the UserControl , provide a button , when click the button , open another RadWindow, let's call it window 2,  Then  leave window 2 open as it is, and click one of the RadComboBox on the  window 1, you will find out that all the combobox has it's dropdown open.

it will looks like the following snapshot.


I attach the sample project here.download

I also submit this issue to Telerik with the sample project , they confirm it is an issue, but no good solution yet.

But I work out a workaround that will collapse the dropdown when it is open without focus. 

I use a behaviour to achieve this, cause behaviour is nice , it can be easily add to the control without messing up the view's code behind. We are quite strictly using MVVM. So  there is very minimal code in the view's code behind.

using System.Windows.Interactivity;
 using Telerik.Windows.Controls;
 using System.Windows;
 /// <summary>
 /// Behavior to close unexpected dropdown behavior
 /// </summary>
 public class RadComboBoxCloseUnexpectedDropdownBehavior : Behavior<RadComboBox>
 {
  /// <summary>
  /// Default Constructor.
  /// </summary>
  public RadComboBoxCloseUnexpectedDropdownBehavior()
  {
   
  }
 
  /// <summary>
  /// When the behavior get attached into Visual Tree.
  /// </summary>
  protected override void OnAttached()
  {
   base.OnAttached();
   if (null == this.AssociatedObject) return;
   this.AssociatedObject.DropDownOpened += new SystemEventHandler(AssociatedObject_DropDownOpened);
 
  }
  void AssociatedObject_DropDownOpened(object sender, SystemEventArgs e)
  {
   if(!this.AssociatedObject.IsEnabled || !this.AssociatedObject.IsFocused)
    this.AssociatedObject.IsDropDownOpen = false;
  }
 
 
  /// <summary>
  /// Check whether keyboard focus is in this control.
  /// </summary>
  /// <param name="element"></param>
  /// <returns></returns>
  bool IsKeyboardFocusWithin(UIElement element)
  {
   UIElement uiElement = FocusManagerHelper.GetFocusedElement((DependencyObject)element) as UIElement;
   if (uiElement != null)
    return ParentOfTypeExtensions.IsAncestorOf((DependencyObject)element, (DependencyObject)uiElement);
   return false;
  }
  /// <summary>
  /// When behavior get removed
  /// </summary>
  protected override void OnDetaching()
  {
   this.AssociatedObject.DropDownOpened -= AssociatedObject_DropDownOpened;
   base.OnDetaching();
  }
 }

In order to use this behavior conveniently in Style, I also create attached property

/// <summary>
    /// Extensions on RadComboBox.
    /// </summary>
    public static class RadComboBoxExtensions
    {
        #region CloseDropdown
        /// <summary>
        /// Gets the <see cref="CloseUnexpectedDropdownProperty"/>
        /// </summary>
        public static readonly DependencyProperty CloseUnexpectedDropdownProperty = DependencyProperty.RegisterAttached(
            "CloseUnexpectedDropdown",
            typeof(bool),
            typeof(RadComboBox), //Note MUST be DepOb to support use in styles
            new PropertyMetadata(OnCloseUnexpectedDropdownChanged));
        
        /// <summary>
        /// Sets the DropOnFocus value
        /// </summary>
        /// <param name="element">Element</param>
        /// <param name="value">Value</param>
        public static void SetCloseUnexpectedDropdown(RadComboBox element, bool value) { element.SetValue(CloseUnexpectedDropdownProperty, value); }
        /// <summary>
        /// Gets the DropOnFocus value
        /// </summary>
        /// <param name="element">Element</param>
        /// <returns>Bool</returns>
        public static bool GetCloseUnexpectedDropdown(RadComboBox element) { return (bool)element.GetValue(CloseUnexpectedDropdownProperty); }
        static void OnCloseUnexpectedDropdownChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var behaviours = Interaction.GetBehaviors(d);
 
            var existing = behaviours.OfType<RadComboBoxCloseUnexpectedDropdownBehavior>().ToList();
 
            if ((e.NewValue is bool) && (bool)e.NewValue)
            {
                if (existing.Count <= 0) behaviours.Add(new RadComboBoxCloseUnexpectedDropdownBehavior());
            }
            else
            {
                foreach (var item in existing) { behaviours.Remove(item); }
            }
 
        }
        #endregion
    }

 I didn't dig into telerik's RadWindow source code to see what actually cause this, but I suspect the window is trying to to set the focus appropriately when it get activated,but I hope Telerik can fix this issue appropriately in their future release.

No comments:

Post a Comment