如何同时获取对象的非公共属性及其值

时间:2013-11-07 09:27:35

标签: c# wpf xaml user-controls propertygrid

如何同时获取对象的所有非公共属性及其值,以便在运行时将对象提供给属性网格以填充其值。

每当选择TreeView的treeviewitem时,场景都是这样的,当树视图中的选择发生变化时,propertygrid会自动更改。

这是xaml文件。

<UserControl x:Class="WpfExperiment.AdditionalProperty"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
               xmlns:wpg="clr-namespace:System.Windows.Controls"

            >

    <UserControl.Resources>
            <DataTemplate DataType="{x:Type sys:String}" x:Key="RadioButtons">
                <RadioButton Margin="0,3" Content="{Binding .}" GroupName="radios" Checked="Item_Checked" />
            </DataTemplate>
            <ObjectDataProvider x:Key="SortTypes" MethodName="GetValues" ObjectType="{x:Type sys:Enum}">
                <ObjectDataProvider.MethodParameters>
                    <x:Type TypeName="wpg:PropertySort"/>
                </ObjectDataProvider.MethodParameters>
            </ObjectDataProvider>


    </UserControl.Resources>
    <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">


        <wpg:WpfPropertyGrid  x:Name="PropertyGrid1" 
            Margin="20,20,118,21" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
            HelpVisible="{Binding ElementName=ShowDescrip, Path=IsChecked}" 
            ToolbarVisible="{Binding ElementName=ShowToolbar, Path=IsChecked}"
            PropertySort="{Binding ElementName=ComboSort, Path=SelectedItem}" />
        <StackPanel Orientation="Vertical"   HorizontalAlignment="Right" VerticalAlignment="Top">
            <TextBlock Margin="0,0,0,10" >Selected Object:</TextBlock>
           <ItemsControl x:Name="ItemList" ItemTemplate="{StaticResource RadioButtons}" Height="100" Visibility="{Binding }" />
            <TextBlock Margin="0,10,0,3" >Selection Type:</TextBlock>

            <TextBlock Margin="0,10,0,3" >Features:</TextBlock>
            <CheckBox Name="ShowDescrip" Margin="0,3,0,3" Content="Help Visible" />
            <CheckBox Name="ShowToolbar" Margin="0,3,0,3" IsChecked="True" Content="Toolbar Visible" />
            <ComboBox Name="ComboSort" Margin="0,3,0,0" Width="95" FontSize="10"
                SelectedIndex="0" ItemsSource="{Binding Source={StaticResource SortTypes}}" />
        </StackPanel>



    </Grid>

</UserControl>

AdditionalProperty.xaml.cs

 /// <summary>
    /// Interaction logic for AdditionalProperty.xaml
    /// </summary>
    public partial class AdditionalProperty : UserControl
    {
        static private Person Person;

        public AdditionalProperty(Person _person)
        {
            Person = _person;
        }

        // names must match the data members
        private object[] ItemArray = { "Person" };
        public AdditionalProperty()
        {
                InitializeComponent();
                this.ItemList.ItemTemplate = this.Resources["RadioButtons"] as DataTemplate;
                this.ItemList.ItemsSource = this.ItemArray;

        }


        private void Item_Checked(object sender, RoutedEventArgs e)
        {

            if (e.Source is RadioButton)
            {

                object selected = this.GetType().GetField("Person",   System.Reflection.BindingFlags.NonPublic).GetValue(this);

               this. PropertyGrid1.SelectedObject = selected;




            }
        }



    }
}

此usercontrol嵌入在这样的窗口控件中。

<Window x:Class="WpfExperiment.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:sys="clr-namespace:System;assembly=mscorlib"
            xmlns:wpg="clr-namespace:System.Windows.Controls"
        xmlns:local="clr-namespace:WpfExperiment"
        Title="MainWindow" Height="350" Width="525">

 <local:AdditionalProperty Grid.Column="1"  />
    </Grid>
</Window>

MainWindow.xaml.cs

public partial class MainWindow : Window
    {
       private Person Person = new Person("Shakti");
       // names must match the data members
       private object[] ItemArray = { "Person"};

        public MainWindow()
        {
            InitializeComponent();
              new AdditionalProperty(Person);

        }
}

WpfPropertyGrid代码:

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;
        }
    }
}

人员类:

  public class Person
    {
        public enum Gender { Male, Female }

        #region private fields
        private string[] _Names = new string[3];
        #endregion

        // The following properties are wrapping an array of strings
        #region Public Properties
        [Category("Name")]
        [DisplayName("First Name")]
        public string FirstName
        {
            set { _Names[0] = value; }
            get { return _Names[0]; }
        }

        [Category("Name")]
        [DisplayName("Mid Name")]
        public string MidName
        {
            set { _Names[1] = value; }
            get { return _Names[1]; }
        }

        [Category("Name")]
        [DisplayName("Last Name")]
        public string LastName
        {
            set { _Names[2] = value; }
            get { return _Names[2]; }
        }

        // The following are autoimplemented properties (C# 3.0 and up)
        [Category("Characteristics")]
        [DisplayName("Gender")]
        public Gender PersonGender { get; set; }

        [Category("Characteristics")]
        [DisplayName("Birth Date")]
        public DateTime BirthDate { get; set; }

        [Category("Characteristics")]
        public int Income { get; set; }

        // Other cases of hidden read-only property and formatted property
        [DisplayName("GUID"), ReadOnly(true), Browsable(true)]   // many attributes defined in the same row
        public string GuidStr
        {
            get { return Guid.ToString(); }
        }

        [Browsable(false)]  // this property will not be displayed
        public System.Guid Guid
        {
            get;
            private set;
        }
        #endregion

        public Person(string name)
        {
            // default values
            for (int i = 0; i < 3; i++)
                _Names[i] = name;
            this.PersonGender = Gender.Male;
            this.Guid = System.Guid.NewGuid();
        }

        public override string ToString()
        {
            return string.Format("{0} {1} {2}", FirstName, MidName, LastName).Trim().Replace("  ", " ");
        }
    }

我无法理解为什么此代码的一部分返回null:

object selected = **this.GetType().GetField("Person",   System.Reflection.BindingFlags.NonPublic)**.GetValue(this);

仅供参考,此代码改编自[http://www.codeproject.com/Articles/87715/Native-WPF-4-PropertyGrid]

2 个答案:

答案 0 :(得分:1)

尝试:

this.GetType().GetField("Person",   
     System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static).GetValue(this)

Suggession:不要使用自己的名称调用实例。避免混淆。

答案 1 :(得分:0)

您可以使用PropertyInfo class执行此操作。尝试这样的事情:

List<object> privatePropertyValues = new List<object>();
foreach (PropertyInfo propertyInfo in this.GetType().GetProperties(
    BindingFlags.NonPublic | BindingFlags.Instance))
{
    //Console.WriteLine("{0}  Type: {1},  Value: {2}", propertyInfo.Name, 
    //  propertyInfo.PropertyType, propertyInfo.GetValue(this));
    privatePropertyValues.Add(propertyInfo.GetValue(this));
}

更新&gt;&gt;&gt;

要获得一个属性,您可以使用Type.GetProperty方法:

PropertyInfo propertyInfo = this.GetType().GetProperty("PropertyName", 
    BindingFlags.NonPublic | BindingFlags.Instance))
object propertyValue = propertyInfo.GetValue(this);

我认为这一切都是正确的,但我现在无法测试,所以如果有任何问题请告诉我。