惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Application and Cybersecurity Blog
Application and Cybersecurity Blog
T
Threat Research - Cisco Blogs
Latest news
Latest news
Project Zero
Project Zero
TaoSecurity Blog
TaoSecurity Blog
Cyberwarzone
Cyberwarzone
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Google DeepMind News
Google DeepMind News
P
Privacy & Cybersecurity Law Blog
T
Troy Hunt's Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
AWS News Blog
AWS News Blog
Hacker News: Ask HN
Hacker News: Ask HN
S
Security @ Cisco Blogs
C
Cisco Blogs
Help Net Security
Help Net Security
I
Intezer
W
WeLiveSecurity
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
腾讯CDC
S
Secure Thoughts
MyScale Blog
MyScale Blog
Recorded Future
Recorded Future
G
GRAHAM CLULEY
L
LINUX DO - 热门话题
A
About on SuperTechFans
C
CXSECURITY Database RSS Feed - CXSecurity.com
IT之家
IT之家
J
Java Code Geeks
The Hacker News
The Hacker News
阮一峰的网络日志
阮一峰的网络日志
Scott Helme
Scott Helme
Recent Announcements
Recent Announcements
AI
AI
Cisco Talos Blog
Cisco Talos Blog
B
Blog RSS Feed
V
Vulnerabilities – Threatpost
C
Check Point Blog
Security Latest
Security Latest
S
SegmentFault 最新的问题
T
The Exploit Database - CXSecurity.com
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
M
MIT News - Artificial intelligence
T
The Blog of Author Tim Ferriss
Attack and Defense Labs
Attack and Defense Labs
PCI Perspectives
PCI Perspectives
Recent Commits to openclaw:main
Recent Commits to openclaw:main
T
Tailwind CSS Blog
Apple Machine Learning Research
Apple Machine Learning Research

博客园 - HotSky

Chrome启用CDP(chrome-devtools-protocol)进行远程操控 WPF 让ScrollViewer支持按住鼠标中键拖拽滚动内容 WPF 让ScrollViewer支持鼠标中键滚动缩放内容 Nodejs使用 nodejs中写sql需要用in时的写法 C#城市最短路径 C#Animation Sqlite PDF附录A: 内容流操作码 WPF FPS类 生命模拟 C# Sql帮助类,可扩展 WPF WriteableBitmap通过GDI+绘制帮助类 Alpha混合 Bmp读写二值图 WPF支持任意快捷键+鼠标组合的绑定类 WPF阻止窗体被系统缩放,使用显示器DPI WPF DataGrid自动增长序号列 C#访问或修改私有类、函数、变量、属性
WPF一个简单的属性编辑控件
HotSky · 2024-05-25 · via 博客园 - HotSky

代码:

    public class PropertiesControl : Grid
    {

        [TypeConverter(typeof(LengthConverter))]
        public double RowHeight
        {
            get { return (double)GetValue(RowHeightProperty); }
            set { SetValue(RowHeightProperty, value); }
        }

        public static readonly DependencyProperty RowHeightProperty =
            DependencyProperty.Register("RowHeight", typeof(double), typeof(PropertiesControl), new PropertyMetadata(0d));

        public object Source
        {
            get { return (object)GetValue(SourceProperty); }
            set { SetValue(SourceProperty, value); }
        }

        public static readonly DependencyProperty SourceProperty =
            DependencyProperty.Register("Source", typeof(object), typeof(PropertiesControl), new PropertyMetadata(SourceChangedCallBack));

        private static void SourceChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            PropertiesControl control = (PropertiesControl)d;
            if (e.OldValue == e.NewValue) return;
            control.Load();
        }

        GridSplitter splitter = new GridSplitter { Width = 2, HorizontalAlignment = HorizontalAlignment.Right };

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            splitter.SetBinding(BackgroundProperty, new Binding { Source = this, Path = new PropertyPath(BackgroundProperty) });
        }

        void Load()
        {
            Children.Clear();
            RowDefinitions.Clear();
            ColumnDefinitions.Clear();
            ColumnDefinitions.Add(new ColumnDefinition());
            ColumnDefinitions.Add(new ColumnDefinition());
            if (Source == null) return;
            PropertyDocument doc = PropertyDocument.Load(Source);
            if (doc.Children != null)
                Load(doc.Children);
            SetRowSpan(splitter, RowDefinitions.Count);
            Children.Add(splitter);
        }

        void Load(List<Property> properties)
        {
            if (properties == null) return;
            foreach (var child in properties)
            {
                RowDefinitions.Add(new RowDefinition());
                if (child.Children != null && child.Children.Count > 0)
                {
                    TextBlock group = new TextBlock { Text = child.PropertyInfo.Name, };
                    SetColumn(group, 0);
                    SetRow(group, RowDefinitions.Count - 1);
                    Children.Add(group);
                    Load(child.Children);
                    continue;
                }
                TextBlock text = new TextBlock { Text = child.PropertyInfo.Name, VerticalAlignment = VerticalAlignment.Center };
                SetColumn(text, 0);
                SetRow(text, RowDefinitions.Count - 1);
                LoadValueControl(child);
                Children.Add(text);
            }
        }

        void LoadValueControl(Property child)
        {
            FrameworkElement element;
            Binding binding = new Binding(child.Path) { Source = Source, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
            if (child.PropertyInfo.PropertyType.IsEnum)
            {
                Array enmus = Enum.GetValues(child.PropertyInfo.PropertyType);
                ComboBox comboBox = new ComboBox { ItemsSource = enmus, VerticalContentAlignment = VerticalAlignment.Center, BorderThickness = new Thickness(0), IsEnabled = !child.CanSet() };
                comboBox.SetBinding(Selector.SelectedItemProperty, binding);
                element = comboBox;
            }
            else if (child.PropertyInfo.PropertyType == typeof(bool))
            {
                CheckBox cb = new CheckBox { VerticalAlignment = VerticalAlignment.Center, IsEnabled = !child.CanSet() };
                cb.SetBinding(CheckBox.IsCheckedProperty, binding);
                element = cb;
            }
            else if (!child.CanSet())
            {
                TextBlock control = new TextBlock { VerticalAlignment = VerticalAlignment.Center };
                control.SetBinding(TextBlock.TextProperty, binding);
                element = control;
            }
            else
            {
                TextBox textBox = new TextBox { VerticalContentAlignment = VerticalAlignment.Center, BorderThickness = new Thickness(0) };
                textBox.SetBinding(TextBox.TextProperty, binding);
                element = textBox;
            }
            SetColumn(element, 1);
            SetRow(element, RowDefinitions.Count - 1);
            if (RowHeight > 0d)
                element.Height = RowHeight;
            element.Margin = new Thickness(0, 2, 0, 0);
            Children.Add(element);
        }
    }

    public class PropertyDocument
    {
        public object Value { get; set; }
        public List<Property>? Children { get; private set; }

        private PropertyDocument(object instance)
        {
            Value = instance;
        }

        public static PropertyDocument? Load(object instance)
        {
            if (instance == null) return null;
            var doc = new PropertyDocument(instance);
            if (instance != null)
                doc.Children = Property.LoadProperties(instance, null, doc);
            return doc;
        }
    }

    public class Property
    {
        public PropertyInfo PropertyInfo { get; set; }
        public Property? Parent { get; set; }
        public List<Property>? Children { get; private set; }
        public PropertyDocument Document { get; set; }
        public string Path
        {
            get
            {
                if (Parent != null)
                    return $"{Parent.Path}.{PropertyInfo.Name}";
                else
                    return $"{PropertyInfo.Name}";
            }
        }

        public Property(PropertyInfo propertyInfo, Property? parent, PropertyDocument doc)
        {
            PropertyInfo = propertyInfo;
            Parent = parent;
            Document = doc;
            Children = LoadProperties(GetValue(), this, Document);
        }

        public object? GetValue()
        {
            return PropertyInfo.GetValue(Parent == null ? Document.Value : Parent.GetValue());
        }

        public bool CanSet()
        {
            return CanSet(PropertyInfo);
        }

        public static bool CanSet(PropertyInfo propertyInfo)
        {
            return propertyInfo.CanWrite && propertyInfo.SetMethod != null && (propertyInfo.SetMethod.Attributes & MethodAttributes.Public) > 0;
        }

        public static bool CanGet(PropertyInfo propertyInfo)
        {
            return propertyInfo.CanRead && propertyInfo.GetMethod != null && (propertyInfo.GetMethod.Attributes & MethodAttributes.Public) > 0;
        }

        public static List<Property>? LoadProperties(object? instance, Property? parent, PropertyDocument doc)
        {
            if(instance == null) return null;
            Type type = instance.GetType();
            object? value;
            List<Property> properties = new List<Property>();
            var ps = type.GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
            if (ps.Length <= 0 || type.IsValueType) return null;
            foreach (var p in ps)
            {
                if (!CanGet(p)) continue;
                value = p.GetValue(instance);
                Property property = new Property(p, parent, doc);
                properties.Add(property);
            }
            return properties;
        }
    }

View Code

使用方式:

<controls:PropertiesControl DockPanel.Dock="Right" Grid.Column="1" Source="{Binding Box}" RowHeight="30" Background="#FFEEEEEE" VerticalAlignment="Top"/>
    public class Box
    {
        public double X { get; set; }
        public double Y { get; set; }
        public double Width { get; set; }
        public double Height { get; set; }
        public Point Origin { get; set; }
        public bool Enabled { get; set; }
        public int Id { get; private set; }
    }
    public class TestVM : NotifyProperty, ITemplateView
    {
        public Box Box { get; set; }

        public TestVM()
        {
            Box = new Box { X = 100, Y = 100, Width = 100, Height = 100 };
        }
    }

直接绑定对象即可。