xceed PropertyGrid 如何做成Visual Studio 的属性窗口样子

类似这样的,我百度了一下,发现使用Xceed 不错。使用PropertyGrid

前台代码为

复制代码
<Window
    x:Class="WpfApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:WpfApp"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
    Title="PropertyGrid Event Example"
    Width="800"
    Height="450"
    d:DataContext="{d:DesignInstance Type=local:MainViewModel}"
    mc:Ignorable="d">
    <Window.Resources>
        <!--  定义转换器  -->
        <local:CommandItemToCommandConverter x:Key="CommandItemToCommandConverter" />
        <!--  定义模板  -->
        <DataTemplate x:Key="EventEditTemplate">
            <StackPanel Orientation="Horizontal">
                <!--  下拉框选择命令  -->
                <ComboBox
                    Width="150"
                    DisplayMemberPath="Name"
                    ItemsSource="{Binding DataContext.ButtonViewModel.Commands, RelativeSource={RelativeSource AncestorType=Window}}"
                    SelectedItem="{Binding DataContext.ButtonViewModel.EventClick, RelativeSource={RelativeSource AncestorType=Window}, Converter={StaticResource CommandItemToCommandConverter}, Mode=TwoWay}" />
            </StackPanel>
        </DataTemplate>

    </Window.Resources>

    <StackPanel Orientation="Vertical">
        <!--  PropertyGrid that binds to the Button object  -->
        <xctk:PropertyGrid Name="MyPropertyGrid" SelectedObject="{Binding ButtonViewModel}">
            <xctk:PropertyGrid.EditorDefinitions>
                <xctk:EditorTemplateDefinition EditingTemplate="{StaticResource EventEditTemplate}" TargetProperties="EventClick" />
            </xctk:PropertyGrid.EditorDefinitions>
        </xctk:PropertyGrid>
        <Button
            Width="100"
            Height="100"
            Command="{Binding ButtonViewModel.EventClick, NotifyOnSourceUpdated=True}"
            Content="sub" />
    </StackPanel>
</Window>

后台代码为

复制代码
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xaml;
using static WpfApp.ButtonViewModel;

namespace WpfApp
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new MainViewModel(); // Set the DataContext to ViewModel
        }
    }
    public class MainViewModel
    {
        public ButtonViewModel ButtonViewModel { get; }

        public MainViewModel()
        {
            ButtonViewModel = new ButtonViewModel();
        }
    }
    public class CommandItemToCommandConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {// 将 ICommand 转换回 CommandItem
            if (value is ICommand command)
            {
                var viewModel = Application.Current.MainWindow.DataContext as ButtonViewModel;
                if (viewModel != null)
                {
                    return viewModel.Commands.FirstOrDefault(item => item.Command == command);
                }
            }
            return null;
            
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            // 从 CommandItem 提取 ICommand
            if (value is CommandItem commandItem)
            {
                return commandItem.Command;
            }
            return null;

        }
    }

    public class CommandItem
    {
        public string Name { get; set; }
        public ICommand Command { get; set; }
    }

    public class ButtonViewModel : INotifyPropertyChanged
    {
        private ICommand _eventClick;

        public ObservableCollection<CommandItem> Commands { get; set; }

        public ICommand EventClick
        {
            get => _eventClick;
            set
            {
                _eventClick = value;
                OnPropertyChanged(nameof(EventClick));
            }
        }

        public ButtonViewModel()
        {
            Commands = new ObservableCollection<CommandItem>
        {
            new CommandItem
            {
                Name = "Say Hello",
                Command = new RelayCommand(_ => MessageBox.Show("Hello!"))
            },
            new CommandItem
            {
                Name = "Say Goodbye",
                Command = new RelayCommand(_ => MessageBox.Show("Goodbye!"))
            }
        };

            // 初始化默认命令
            EventClick = Commands.FirstOrDefault()?.Command;
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }



    public class RelayCommand : ICommand
    {
        private readonly Action<object> _execute;
        private readonly Predicate<object> _canExecute;

        public RelayCommand(Action<object> execute) : this(execute, null)
        { }

        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
        {
            _execute = execute ?? throw new ArgumentNullException(nameof(execute));
            _canExecute = canExecute;
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
    }
}

这是一个完整可以运行的例子。其实要做成vs 那样的,路途很遥远,这里只是举个例子,需要重写很多模板,像前面的代码中就是定义了Event 选择的模板

实际运行效果如下:

相关推荐
聆风吟º7 小时前
CANN hccl 深度解析:异构计算集群通信库的跨节点通信与资源管控实现逻辑
人工智能·wpf·transformer·cann
先跑起来再说9 小时前
Git 入门到实战:一篇搞懂安装、命令、远程仓库与 IDEA 集成
ide·git·后端·elasticsearch·golang·intellij-idea
LYOBOYI12311 小时前
vscode界面美化
ide·vscode·编辑器
无心水15 小时前
分布式定时任务与SELECT FOR UPDATE:从致命陷阱到优雅解决方案(实战案例+架构演进)
服务器·人工智能·分布式·后端·spring·架构·wpf
LZL_SQ17 小时前
HCCL测试框架中AllReduce边界条件测试设计深度剖析
wpf·cann
骥龙1 天前
第六篇:AI平台篇 - 从Jupyter Notebook到生产级模型服务
ide·人工智能·jupyter
kun200310291 天前
如何用Obsidian+VSCode生成文案排版并发布到公众号
ide·vscode·编辑器
JQLvopkk2 天前
C# 实践AI :Visual Studio + VSCode 组合方案
人工智能·c#·visual studio
User_芊芊君子2 天前
【分布式训练】CANN SHMEM跨设备内存通信库:构建高效多机多卡训练的关键组件
分布式·深度学习·神经网络·wpf
踏过山河,踏过海2 天前
【qt-查看对应的依赖的一种方法】
qt·visual studio