This question is locked. New answers and comments are not allowed.
Hi All,
I am adding one silverlight DataGrid inside the raddropdown button. The idea is we wanted to have a control which will give us a grid in the dropdown in place of a normal list in the dropdown. The problem is when we are adding items source to it and setting the items selection (do remember the dropdown is closed that is isOpen=false) and then when the user clicks on the dropdown button the contol is automatically firing a selection changed event for the DataGrid. To solve this problem we tried assigning the selectionchanged event handler after setting up the itemsource..but still no use. That also does not worked.
What we figured out is as soon as the selection is changed the grid is firing a selction changed event. But as the grid is in closed position the event is not getting properly executed. So as soon as somebody clicks on the open button the event is getting fired. Also inside the selectionchanged event handler we kept the code of closing the dropdown as IsOpen=false. But when it is happening for the first time. That is when after setting the selection of the grid for the first time through code when the user clicks the dropdownbutton then selectionchanged event handler is getting called and as a result the isopen=false is also getting executed. And it is giving a COM error. So we tried executing it through despatcher like this
But as I told you the event handler is getting called for the first time automatically...so we ended up getting a flicker when the user clicks it for the first time. The dropdown opens and closes automically. Then again the user will have to click it and finally the dropdown opens.
So as I told you we need a dropdown control with a grid in it. If you think the control we are using is not correct one..do suggest us. Also If you think there are ways to fix this issue please do let us know. Also below is the whole source code of the control
Hope this helps. Please do let me know if you have any question about any part of the code
Regards
Tiklu
I am adding one silverlight DataGrid inside the raddropdown button. The idea is we wanted to have a control which will give us a grid in the dropdown in place of a normal list in the dropdown. The problem is when we are adding items source to it and setting the items selection (do remember the dropdown is closed that is isOpen=false) and then when the user clicks on the dropdown button the contol is automatically firing a selection changed event for the DataGrid. To solve this problem we tried assigning the selectionchanged event handler after setting up the itemsource..but still no use. That also does not worked.
What we figured out is as soon as the selection is changed the grid is firing a selction changed event. But as the grid is in closed position the event is not getting properly executed. So as soon as somebody clicks on the open button the event is getting fired. Also inside the selectionchanged event handler we kept the code of closing the dropdown as IsOpen=false. But when it is happening for the first time. That is when after setting the selection of the grid for the first time through code when the user clicks the dropdownbutton then selectionchanged event handler is getting called and as a result the isopen=false is also getting executed. And it is giving a COM error. So we tried executing it through despatcher like this
this.Dispatcher.BeginInvoke(() => { this.IsOpen = false; });But as I told you the event handler is getting called for the first time automatically...so we ended up getting a flicker when the user clicks it for the first time. The dropdown opens and closes automically. Then again the user will have to click it and finally the dropdown opens.
So as I told you we need a dropdown control with a grid in it. If you think the control we are using is not correct one..do suggest us. Also If you think there are ways to fix this issue please do let us know. Also below is the whole source code of the control
using System;using System.Windows;using System.Windows.Controls;using System.Windows.Input;using System.Windows.Media;using Telerik.Windows.Controls;using System.Linq;using System.ComponentModel;using System.Collections;using System.Collections.Generic;using System.Windows.Data;namespace Phoenix.Controlkit.Module{ [Description("This is a Custom Dropdown Control with a Grid")] public class PhoenixCustomDropdown : RadDropDownButton, IPhoenixClearAction { #region Private Members protected TextBlock lblContent; protected DataGrid grid; protected int itemCount; #endregion #region CTOR public PhoenixCustomDropdown() : base() { this.lblContent = new TextBlock(); this.lblContent.Padding = new Thickness(10, 0, 0, 0); this.HorizontalContentAlignment = HorizontalAlignment.Left; this.Content = this.lblContent; //now the grid SetupGrid(); //this.Height = 25; this.itemCount = 0; } /// <summary> /// This method is actually setting up the grid /// </summary> protected void SetupGrid() { this.grid = new DataGrid(); this.grid.HeadersVisibility = DataGridHeadersVisibility.Column; this.grid.IsReadOnly = true; this.grid.SelectionMode = DataGridSelectionMode.Single; this.grid.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden; //this.grid.SelectionChanged += grid_SelectionChanged; this.grid.LayoutUpdated += new EventHandler(grid_LayoutUpdated); this.grid.MouseLeftButtonDown += (o, e) => { e.Handled = true; }; this.grid.MouseLeftButtonUp += (o, e) => { this.Dispatcher.BeginInvoke(() => { this.IsOpen = false; }); }; SolidColorBrush grdBack = new SolidColorBrush(Colors.Transparent); this.grid.RowBackground = grdBack; this.grid.AlternatingRowBackground = grdBack; this.DropDownContent = this.grid; } private void SetupBinding() { //for label var textBinding = new Binding(this.DisplayMemberPath); textBinding.Mode = BindingMode.TwoWay; this.lblContent.DataContext = this.grid.SelectedItem; this.lblContent.SetBinding(TextBlock.TextProperty, textBinding); } #endregion #region Event Handlers protected override void OnKeyDown(KeyEventArgs e) { base.OnKeyDown(e); switch (e.Key) { case Key.Down: if (this.grid.SelectedIndex < this.itemCount) this.grid.SelectedIndex++; break; case Key.Up: if (this.grid.SelectedIndex > 0) this.grid.SelectedIndex--; break; } } protected override void OnGotFocus(RoutedEventArgs e) { base.OnGotFocus(e); //this.Background = new SolidColorBrush(Colors.Orange); this.grid.Focus(); } /// <summary> /// This is the event handler for grids selection change. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void grid_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) { SelectValues(); this.Dispatcher.BeginInvoke(() => { this.IsOpen = false; }); } private void SelectValues() { this.lblContent.DataContext = this.grid.SelectedItem; this.SelectedItem = this.grid.SelectedItem; this.SelectedValue = GetMemberValue(this.SelectedItem); } /// <summary> /// for implementing the onevent pattern /// </summary> /// <param name="e"></param> protected virtual void OnSelectionChanged(System.Windows.Controls.SelectionChangedEventArgs e) { if (this.SelectionChanged != null) { this.SelectionChanged(this, e); } } void grid_LayoutUpdated(object sender, EventArgs e) { double width = 15; foreach (var col in this.grid.Columns) { width += col.ActualWidth; } this.grid.Width = (width > this.MinWidth) ? width : this.MinWidth; if (grid.ItemsSource != null) { double height = 12; foreach (var item in grid.ItemsSource) { height += 25; if (height > 160) break; } grid.Height = height; } } #endregion #region Properties #region Text /// <summary> /// The text property. It returns the text of the /// current combobox selection /// </summary> public string Text { get { return this.lblContent.Text; } set { this.lblContent.Text = value; } } #endregion #region GridHeight public static DependencyProperty GridHeightProperty = DependencyProperty.Register("GridHeight", typeof(double), typeof(PhoenixCustomDropdown), new PropertyMetadata( (o, e) => { ((PhoenixCustomDropdown)o).grid.Height = (double)e.NewValue; } )); /// <summary> /// The height of the grid /// </summary> public double GridHeight { get { return (double)GetValue(GridHeightProperty); } set { SetValue(GridHeightProperty, value); } } #endregion #region ItemsSource public static DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(PhoenixCustomDropdown), new PropertyMetadata( (o, e) => { if (e.NewValue == null) return; PhoenixCustomDropdown cdd = (PhoenixCustomDropdown)o; cdd.grid.SelectionChanged -= cdd.grid_SelectionChanged; cdd.IsOpen = true; IList lst = (IList)e.NewValue; cdd.itemCount = lst.Count; if (cdd.DefaultValueText != null) { if (cdd.itemCount > 0) { var first = lst[0]; var blank = Activator.CreateInstance(first.GetType()); blank.GetType().GetProperty(cdd.DisplayMemberPath).SetValue(blank, cdd.DefaultValueText, null); List<object> result = new List<object>(); result.Add(blank); result.AddRange(lst); cdd.grid.ItemsSource = result; if (cdd.SelectedValue == null) cdd.SelectedValue = blank.GetType().GetProperty(cdd.ValueMemberPath).GetValue(blank, null); cdd.SetupBinding(); } else { cdd.Text = cdd.DefaultValueText; cdd.SetupGrid(); //lets try resetting the grid once cdd.SetupColumns(cdd.Columns); cdd.grid.ItemsSource = lst; cdd.grid.SelectedItem = null; } } else { cdd.grid.ItemsSource = lst; cdd.grid.SelectedItem = null; } if (cdd.DefaultDisplayColumn != null) { var deflt = ( from object itm in cdd.grid.ItemsSource where (bool)itm.GetType().GetProperty(cdd.DefaultDisplayColumn).GetValue(itm, null) select itm ).FirstOrDefault(); if (deflt != null) { if (cdd.SelectedValue == null) cdd.SelectedValue = deflt.GetType().GetProperty(cdd.ValueMemberPath).GetValue(deflt, null); } } cdd.SetSelectionFromValue(); cdd.Dispatcher.BeginInvoke(() => { cdd.IsOpen = false; cdd.grid.SelectionChanged += cdd.grid_SelectionChanged; }); } )); /// <summary> /// The items source to be used for displaying the items in the grid /// </summary> public IEnumerable ItemsSource { get { return this.grid.ItemsSource; } set { SetValue(ItemsSourceProperty, value); } } #endregion #region SelectedItem public static DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(PhoenixCustomDropdown), new PropertyMetadata( (o, e) => { var cdd = (PhoenixCustomDropdown)o; List<object> addeditems = new List<object>(); List<object> removeditems = new List<object>(); addeditems.Add(e.NewValue); removeditems.Add(e.OldValue); cdd.OnSelectionChanged(new System.Windows.Controls.SelectionChangedEventArgs(removeditems, addeditems)); } )); /// <summary> /// This property gives the selected item /// </summary> [Description("This will return a single selected item from the items source")] public object SelectedItem { get { return ((object)(GetValue(PhoenixCustomDropdown.SelectedItemProperty))); } set { SetValue(PhoenixCustomDropdown.SelectedItemProperty, value); } } #endregion #region DisplayMemberPath public static DependencyProperty DisplayMemberPathProperty = DependencyProperty.Register("DisplayMemberPath", typeof(string), typeof(PhoenixCustomDropdown), null); /// <summary> /// Here you can set column name of the grid to be displayed in the selected textbox /// </summary> public string DisplayMemberPath { get { return ((string)(this.GetValue(PhoenixCustomDropdown.DisplayMemberPathProperty))); } set { this.SetValue(PhoenixCustomDropdown.DisplayMemberPathProperty, value); } } #endregion #region DefaultText /// <summary> /// This is the text which is going to come when there /// is no other values added to it. /// for example it will display none if you select nothing. /// </summary> [Description("Add the default value text which will be displayed by default in case there is no data selected")] public string DefaultValueText { get; set; } #endregion #region DefaultDisplayColumn [Description("Here you can add the default display column name which will be used for selecting the default value")] public string DefaultDisplayColumn { set; get; } #endregion #endregion #region copied code /// <summary> /// Returns the value from a particular record /// </summary> /// <param name="item">The single record to evaluate</param> /// <returns>The value memeber value</returns> private object GetMemberValue(object item) { return item.GetType().GetProperty(ValueMemberPath).GetValue(item, null); } private object GetMemberDisplay(object item) { try { return item.GetType().GetProperty(DisplayMemberPath).GetValue(item, null); } catch (Exception) { return null; } } public static DependencyProperty ValueMemberPathProperty = DependencyProperty.Register("ValueMemberPath", typeof(string), typeof(PhoenixCustomDropdown), null); /// <summary> /// The name of the colum whos value will be returned while a single item is selected /// </summary> public string ValueMemberPath { get { return ((string)(base.GetValue(PhoenixCustomDropdown.ValueMemberPathProperty))); } set { base.SetValue(PhoenixCustomDropdown.ValueMemberPathProperty, value); } } public static DependencyProperty SelectedValueProperty = DependencyProperty.Register("SelectedValue", typeof(object), typeof(PhoenixCustomDropdown), new PropertyMetadata((o, e) => { //((PhoenixCustomDropdown)o).SetSelectionFromValue(); })); /// <summary> /// The selected value,based on the selection /// </summary> public object SelectedValue { get { return GetValue(PhoenixCustomDropdown.SelectedValueProperty); } set { SetValue(PhoenixCustomDropdown.SelectedValueProperty, value); } } private void SetSelectionFromValue() { var value = SelectedValue; if (ItemsSource != null && value != null) { var sel = (from object item in this.grid.ItemsSource where GetMemberValue(item).Equals(value) select item).FirstOrDefault(); if (sel == null) { //try to get the blank value sel = (from object itm in this.grid.ItemsSource where GetMemberDisplay(itm).Equals(this.DefaultValueText) select itm).FirstOrDefault(); } if (sel != null) { this.grid.SelectionChanged -= this.grid_SelectionChanged; this.grid.SelectedItem = sel; SelectValues(); this.grid.SelectionChanged += this.grid_SelectionChanged; } } } #endregion #region Public Methods [Description("Please do handle this event in case you want to do something specific while the selection of the combobox is changed")] public event System.Windows.Controls.SelectionChangedEventHandler SelectionChanged; protected string _cols; /// <summary> /// This is where we are going to pass the columns /// The format should be col1,col2,col3 etc. /// </summary> public string Columns { set { this._cols = value; SetupColumns(value); } get { return this._cols; } } /// <summary> /// Setup the grid /// </summary> /// <param name="value"></param> private void SetupColumns(string value) { this.grid.AutoGenerateColumns = false; this.grid.Columns.Clear(); foreach (string col in value.Split(',')) { string[] vals = col.Split('|'); DataGridTextColumn dtcol = new DataGridTextColumn(); dtcol.Binding = new System.Windows.Data.Binding(vals[0]); dtcol.Width = DataGridLength.SizeToCells; dtcol.Header = (vals.Length > 1 ? vals[1] : vals[0]); this.grid.Columns.Add(dtcol); } if (grid.Columns.Count == 1) { this.grid.HeadersVisibility = DataGridHeadersVisibility.None; this.grid.GridLinesVisibility = DataGridGridLinesVisibility.None; } } #endregion #region IPhoenixClearAction Members public void Reset() { var blank = (from object itm in this.ItemsSource where GetMemberDisplay(itm).Equals(this.DefaultValueText) select itm).FirstOrDefault(); this.grid.SelectedItem = blank; } #endregion }}Hope this helps. Please do let me know if you have any question about any part of the code
Regards
Tiklu