| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376 | // *********************************************************************// PLEASE DO NOT REMOVE THIS DISCLAIMER//// WpfPropertyGrid - By Jaime Olivares// July 11, 2011// Article site: http://www.codeproject.com/KB/grid/WpfPropertyGrid.aspx// Author site: www.jaimeolivares.com// License: Code Project Open License (CPOL)//// *********************************************************************using System.Activities.Presentation;using System.Activities.Presentation.Model;using System.Activities.Presentation.View;using System.ComponentModel;using System.Reflection;using System.Windows.Data;namespace System.Windows.Controls{    public enum PropertySort    {        NoSort = 0,        Alphabetical = 1,        Categorized = 2,        CategorizedAlphabetical = 3    };     /// <summary>WPF Native PropertyGrid class, uses Workflow Foundation's PropertyInspector</summary>    public class WpfPropertyGrid : Grid    {        #region Private fields        private WorkflowDesigner Designer;        private MethodInfo RefreshMethod;        private MethodInfo OnSelectionChangedMethod;        private MethodInfo IsInAlphaViewMethod;        private TextBlock SelectionTypeLabel;        private Control PropertyToolBar;        private Border HelpText;        private GridSplitter Splitter;        private double HelpTextHeight = 60;        #endregion        #region Public properties        /// <summary>Get or sets the selected object. Can be null.</summary>        public object SelectedObject        {            get { return GetValue(SelectedObjectProperty); }            set { SetValue(SelectedObjectProperty, value); }        }        /// <summary>Get or sets the selected object collection. Returns empty array by default.</summary>        public object[] SelectedObjects        {            get { return GetValue(SelectedObjectsProperty) as object[]; }            set { SetValue(SelectedObjectsProperty, value); }        }        /// <summary>XAML information with PropertyGrid's font and color information</summary>        /// <seealso>Documentation for WorkflowDesigner.PropertyInspectorFontAndColorData</seealso>        public string FontAndColorData        {            set             {                 Designer.PropertyInspectorFontAndColorData = value;             }        }        /// <summary>Shows the description area on the top of the control</summary>        public bool HelpVisible        {            get { return (bool)GetValue(HelpVisibleProperty); }            set { SetValue(HelpVisibleProperty, value); }        }        /// <summary>Shows the tolbar on the top of the control</summary>        public bool ToolbarVisible        {            get { return (bool)GetValue(ToolbarVisibleProperty); }            set { SetValue(ToolbarVisibleProperty, value); }        }        public PropertySort PropertySort        {            get { return (PropertySort)GetValue(PropertySortProperty); }            set { SetValue(PropertySortProperty, value); }        }        #endregion        #region Dependency properties registration        public static readonly DependencyProperty SelectedObjectProperty =            DependencyProperty.Register("SelectedObject", typeof(object), typeof(WpfPropertyGrid),            new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, SelectedObjectPropertyChanged));        public static readonly DependencyProperty SelectedObjectsProperty =            DependencyProperty.Register("SelectedObjects", typeof(object[]), typeof(WpfPropertyGrid),            new FrameworkPropertyMetadata(new object[0], FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, SelectedObjectsPropertyChanged, CoerceSelectedObjects));        public static readonly DependencyProperty HelpVisibleProperty =            DependencyProperty.Register("HelpVisible", typeof(bool), typeof(WpfPropertyGrid),            new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, HelpVisiblePropertyChanged));        public static readonly DependencyProperty ToolbarVisibleProperty =            DependencyProperty.Register("ToolbarVisible", typeof(bool), typeof(WpfPropertyGrid),            new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, ToolbarVisiblePropertyChanged));        public static readonly DependencyProperty PropertySortProperty =            DependencyProperty.Register("PropertySort", typeof(PropertySort), typeof(WpfPropertyGrid),            new FrameworkPropertyMetadata(PropertySort.CategorizedAlphabetical, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, PropertySortPropertyChanged));        #endregion        #region Dependency properties events        private static object CoerceSelectedObject(DependencyObject d, object value)        {            WpfPropertyGrid pg = d as WpfPropertyGrid;            object[] collection = pg.GetValue(SelectedObjectsProperty) as object[];            return collection.Length == 0 ? null : value;        }        private static object CoerceSelectedObjects(DependencyObject d, object value)        {            WpfPropertyGrid pg = d as WpfPropertyGrid;            object single = pg.GetValue(SelectedObjectsProperty);            return single == null ? new object[0] : value;        }        private static void SelectedObjectPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)        {            WpfPropertyGrid pg = source as WpfPropertyGrid;            pg.CoerceValue(SelectedObjectsProperty);            if (e.NewValue == null)            {                pg.OnSelectionChangedMethod.Invoke(pg.Designer.PropertyInspectorView, new object[] { null });                pg.SelectionTypeLabel.Text = string.Empty;            }            else            {                var context = new EditingContext();                var mtm = new ModelTreeManager(context);                mtm.Load(e.NewValue);                Selection selection = Selection.Select(context, mtm.Root);                pg.OnSelectionChangedMethod.Invoke(pg.Designer.PropertyInspectorView, new object[] { selection });                pg.SelectionTypeLabel.Text = e.NewValue.GetType().Name;            }            pg.ChangeHelpText(string.Empty, string.Empty);        }        private static void SelectedObjectsPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)        {            WpfPropertyGrid pg = source as WpfPropertyGrid;            pg.CoerceValue(SelectedObjectsProperty);            object[] collection = e.NewValue as object[];            if (collection.Length == 0)            {                pg.OnSelectionChangedMethod.Invoke(pg.Designer.PropertyInspectorView, new object[] { null });                pg.SelectionTypeLabel.Text = string.Empty;            }            else            {                bool same = true;                Type first = null;                var context = new EditingContext();                var mtm = new ModelTreeManager(context);                Selection selection = null;                // Accumulates the selection and determines the type to be shown in the top of the PG                for (int i = 0; i < collection.Length; i++)                {                    mtm.Load(collection[i]);                    if (i == 0)                    {                        selection = Selection.Select(context, mtm.Root);                        first = collection[0].GetType();                    }                    else                    {                        selection = Selection.Union(context, mtm.Root);                        if (!collection[i].GetType().Equals(first))                            same = false;                    }                }                pg.OnSelectionChangedMethod.Invoke(pg.Designer.PropertyInspectorView, new object[] { selection });                pg.SelectionTypeLabel.Text = same ? first.Name + " <multiple>" : "Object <multiple>";            }            pg.ChangeHelpText(string.Empty, string.Empty);        }        private static void HelpVisiblePropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)        {            WpfPropertyGrid pg = source as WpfPropertyGrid;            if (e.NewValue != e.OldValue)            {                if (e.NewValue.Equals(true))                {                    pg.RowDefinitions[1].Height = new GridLength(5);                    pg.RowDefinitions[2].Height = new GridLength(pg.HelpTextHeight);                }                else                {                    pg.HelpTextHeight = pg.RowDefinitions[2].Height.Value;                    pg.RowDefinitions[1].Height = new GridLength(0);                    pg.RowDefinitions[2].Height = new GridLength(0);                }            }                }        private static void ToolbarVisiblePropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)        {            WpfPropertyGrid pg = source as WpfPropertyGrid;            pg.PropertyToolBar.Visibility = e.NewValue.Equals(true) ? Visibility.Visible : Visibility.Collapsed;        }        private static void PropertySortPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)        {            WpfPropertyGrid pg = source as WpfPropertyGrid;            PropertySort sort = (PropertySort)e.NewValue;            bool isAlpha = (sort == PropertySort.Alphabetical || sort == PropertySort.NoSort);            pg.IsInAlphaViewMethod.Invoke(pg.Designer.PropertyInspectorView, new object[] { isAlpha });        }        #endregion        /// <summary>Default constructor, creates the UIElements including a PropertyInspector</summary>        public WpfPropertyGrid()        {            this.ColumnDefinitions.Add(new ColumnDefinition());            this.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Star) });            this.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(0) });            this.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(0) });            this.Designer = new WorkflowDesigner();            TextBlock title = new TextBlock()            {                Visibility = Windows.Visibility.Visible,                TextWrapping = TextWrapping.NoWrap,                TextTrimming = TextTrimming.CharacterEllipsis,                FontWeight = FontWeights.Bold            };            TextBlock descrip = new TextBlock()            {                Visibility = Windows.Visibility.Visible,                TextWrapping = TextWrapping.Wrap,                TextTrimming = TextTrimming.CharacterEllipsis            };            DockPanel dock = new DockPanel()            {                Visibility = Windows.Visibility.Visible,                LastChildFill = true,                Margin = new Thickness(3,0,3,0)            };            title.SetValue(DockPanel.DockProperty, Dock.Top);            dock.Children.Add(title);            dock.Children.Add(descrip);            this.HelpText = new Border()            {                Visibility = Windows.Visibility.Visible,                BorderBrush = SystemColors.ActiveBorderBrush,                Background = SystemColors.ControlBrush,                BorderThickness = new Thickness(1),                Child = dock            };            this.Splitter = new GridSplitter()             {                 Visibility = Windows.Visibility.Visible,                ResizeDirection = GridResizeDirection.Rows,                 Height=5,                 HorizontalAlignment= Windows.HorizontalAlignment.Stretch            };            var inspector = Designer.PropertyInspectorView;            inspector.Visibility = Visibility.Visible;            inspector.SetValue(FrameworkElement.VerticalAlignmentProperty, VerticalAlignment.Stretch);            this.Splitter.SetValue(Grid.RowProperty, 1);            this.Splitter.SetValue(Grid.ColumnProperty, 0);            this.HelpText.SetValue(Grid.RowProperty, 2);            this.HelpText.SetValue(Grid.ColumnProperty, 0);            Binding binding = new Binding("Parent.Background");            title.SetBinding(BackgroundProperty, binding);            descrip.SetBinding(BackgroundProperty, binding);            this.Children.Add(inspector);            this.Children.Add(this.Splitter);            this.Children.Add(this.HelpText);            Type inspectorType = inspector.GetType();            var props = inspectorType.GetProperties(Reflection.BindingFlags.Public | Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Instance |                Reflection.BindingFlags.DeclaredOnly);            var methods = inspectorType.GetMethods(Reflection.BindingFlags.Public | Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Instance |                Reflection.BindingFlags.DeclaredOnly);            this.RefreshMethod = inspectorType.GetMethod("RefreshPropertyList",                Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Instance | Reflection.BindingFlags.DeclaredOnly);            this.IsInAlphaViewMethod = inspectorType.GetMethod("set_IsInAlphaView",                Reflection.BindingFlags.Public | Reflection.BindingFlags.Instance | Reflection.BindingFlags.DeclaredOnly);            this.OnSelectionChangedMethod = inspectorType.GetMethod("OnSelectionChanged",                 Reflection.BindingFlags.Public | Reflection.BindingFlags.Instance | Reflection.BindingFlags.DeclaredOnly);            this.SelectionTypeLabel = inspectorType.GetMethod("get_SelectionTypeLabel",                Reflection.BindingFlags.Public | Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Instance |                Reflection.BindingFlags.DeclaredOnly).Invoke(inspector, new object[0]) as TextBlock;            this.PropertyToolBar = inspectorType.GetMethod("get_PropertyToolBar",                Reflection.BindingFlags.Public | Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Instance |                Reflection.BindingFlags.DeclaredOnly).Invoke(inspector, new object[0]) as Control;            inspectorType.GetEvent("GotFocus").AddEventHandler(this,                Delegate.CreateDelegate(typeof(RoutedEventHandler), this, "GotFocusHandler", false));            this.SelectionTypeLabel.Text = string.Empty;        }        /// <summary>Updates the PropertyGrid's properties</summary>        public void RefreshPropertyList()        {            RefreshMethod.Invoke(Designer.PropertyInspectorView, new object[] { false });        }        /// <summary>Traps the change of focused property and updates the help text</summary>        /// <param name="sender">Not used</param>        /// <param name="args">Points to the source control containing the selected property</param>        private void GotFocusHandler(object sender, RoutedEventArgs args)        {            //if (args.OriginalSource is TextBlock)            //{                string title = string.Empty;                string descrip = string.Empty;                var theSelectedObjects = this.GetValue(SelectedObjectsProperty) as object[];                if (theSelectedObjects != null && theSelectedObjects.Length > 0)                {                    Type first = theSelectedObjects[0].GetType();                    for (int i = 1; i < theSelectedObjects.Length; i++)                    {                        if (!theSelectedObjects[i].GetType().Equals(first))                        {                            ChangeHelpText(title, descrip);                            return;                        }                    }                    object data = (args.OriginalSource as FrameworkElement).DataContext;                    PropertyInfo propEntry = data.GetType().GetProperty("PropertyEntry");                    if (propEntry == null)                    {                        propEntry = data.GetType().GetProperty("ParentProperty");                    }                    if (propEntry != null)                    {                        object propEntryValue = propEntry.GetValue(data, null);                        string propName = propEntryValue.GetType().GetProperty("PropertyName").GetValue(propEntryValue, null) as string;                        title = propEntryValue.GetType().GetProperty("DisplayName").GetValue(propEntryValue, null) as string;                        PropertyInfo property = theSelectedObjects[0].GetType().GetProperty(propName);                        object[] attrs = property.GetCustomAttributes(typeof(DescriptionAttribute), true);                        if (attrs != null && attrs.Length > 0)                            descrip = (attrs[0] as DescriptionAttribute).Description;                    }                    ChangeHelpText(title, descrip);                }            //}        }        /// <summary>Changes the text help area contents</summary>        /// <param name="title">Title in bold</param>        /// <param name="descrip">Description with ellipsis</param>        private void ChangeHelpText(string title, string descrip)        {            DockPanel dock = this.HelpText.Child as DockPanel;            (dock.Children[0] as TextBlock).Text = title;            (dock.Children[1] as TextBlock).Text = descrip;        }    }}
 |