【问题标题】:How to add or remove DisplayAttribute programmatically in WPF如何在 WPF 中以编程方式添加或删除 DisplayAttribute
【发布时间】:2020-03-01 20:42:18
【问题描述】:

我通过以下方式在我的 UI 中创建一些项目

Buttons.cs

[Browsable(true)]
[Display(Order = 1, Name = "Object1", GroupName = "Objects", ResourceType typeof(Resources.DisplayNames) , AutoGenerateField =false)]

public ButtonViewModel Button1{ get; set; }

[Browsable(true)]
[Display(Order = 2, Name = "Object2", GroupName = "Objects", ResourceType typeof(Resources.DisplayNames) , AutoGenerateField =false)]

public ButtonViewModel Button2{ get; set; }

//etc

我试图做的是根据某些条件显示或隐藏这些 UI 元素。 我看到如果我将 AutoGenerateField 设置为 true/false,我会得到想要的结果,有没有办法在运行时设置该值 true/false? (如果可能的话)

还有其他方法可以一起完成吗?就像每次添加/删除显示属性一样。

编辑

PropertyGridView.xaml

<Grid>       
        <telerik:RadPropertyGrid telerik:StyleManager.Theme="Fluent"  
                                 x:Name="PropertyGrid"
                                 IsGrouped="True"
                                 Item="{Binding SelectedItem}"
                                 PropertySetMode="Union"
                                 RenderMode="Flat"                                                               
                                 SortAndGroupButtonsVisibility="Collapsed">           
        </telerik:RadPropertyGrid>
    </Grid>

PropertyGridViewModel.cs


    public class PropertyGridViewModel : Screen, IPropertyGridViewModel, IHandle<ItemSelectionMessage>
    {
        private IEventAggregator _eventAggregator;

        private IItem _item;

        public PropertyGridViewModel(IEventAggregator eventAggregator)
        {
            _eventAggregator = eventAggregator;

        }

        protected override void OnActivate()
        {
            base.OnActivate();
            _eventAggregator.Subscribe(this);
        }

        protected override void OnDeactivate(bool close)
        {
            base.OnDeactivate(close);
            _eventAggregator.Unsubscribe(this);
        }

        public IItem SelectedItem
        {
            get
            {
                return _item;
            }
            set
            {
                _item = value;
                NotifyOfPropertyChange(() => SelectedItem);
            }
        }

        public void Handle(ItemSelectionMessage message)
        {
            SelectedItem = message.Item;
        }  

    }


而被传递的项目是上面的Buttons.cs。

【问题讨论】:

  • 您需要创建可见性转换器IValueConverter 将您的模型属性转换为元素可见性可能重复stackoverflow.com/questions/14692461/…
  • 我一开始尝试这样做,但是可见性属性只隐藏/显示按钮,并不会影响通常显示在按钮旁边的名称属性。我不知道是我做错了什么还是我遗漏了一些明显的东西。
  • 能否提供您的 xaml 布局,好吗?一般来说,您可以使用按钮和标签隐藏占位符。
  • 您可以在运行时添加/删除属性(请参阅stackoverflow.com/questions/14663763/…),但这并不是您想要实现的最佳方式。如果您想同时显示/隐藏多个控件,您可以简单地将它们包装在同一个 StackPanel 中,然后使用 @OlegBondarenko 所说的 IValueConverter 将绑定添加到 Visibility 参数,或者使用设置的 DataTriggers 添加样式它的可见性。
  • 我更新了上面的代码,你有什么例子可以说明如何实现你的建议吗?

标签: c# wpf


【解决方案1】:

您可以为每个可见性状态创建两个实现IItem 接口的类,并根据当前可见性状态将适当的一个设置为RadPropertyGrid。但它仅适用于不大量的可见性状态(您必须为每个状态创建单独的类)。 另一种方法是为每个具有反射的属性动态设置Display 属性。但我建议您按照第一种方法拆分类。

            // additional methods for getting appropriate instance of your class  
            public static List<Type> GetInterfaceTypes<Interface>()
            {
                Type serachInterface = typeof(Interface);

                List<Type> findClasses = serachInterface.Assembly.GetTypes().Where
                            (
                                t => t.IsClass && !t.IsAbstract &&
                                serachInterface.IsAssignableFrom(t)
                            ).ToList();

                return findClasses;
            }
            public static List<Interface> GetInstances<Interface>(params object[] paramArray)
            {
                List<Interface> returnInstances = new List<Interface>();
                List<Type> foundTypes = GetInterfaceTypes<Interface>();

                foundTypes.ForEach(x =>
                {
                    returnInstances.Add((Interface)Activator.CreateInstance(x,args:paramArray));
                });
                return returnInstances;
            }
           // your handler from PropertyGridViewModel.cs
            public IItem SelectedItem { get; private set; }
            public  void Handle(ItemSelectionMessage message)
            {
                IItem item = GetInstances<IItem>(_eventAggregator).FirstOrDefault(x => x.Visibility == message.Visibility);
                SelectedItem = item;
            }

            public class ItemSelectionMessage
           {
             public VisibilityStates Visibility { set; get; }

           }

    // enum that  is describe you visibility states
        public enum VisibilityStates
        {
            Button1,
            Button2
        }
    // interface and classes that are implemented visibility interface
        public interface IItem
        {
            VisibilityStates Visibility { get; }
        }

        public class Button1StateClass : IItem
        {
             public VisibilityStates Visibility { get => VisibilityStates.Button1; }

              [Browsable(true)]
              [Display(Order = 1, Name = "Object1", GroupName = "Objects", ResourceType typeof(Resources.DisplayNames), AutoGenerateField = true)]

                public ButtonViewModel Button1 { get; set; }
 public Button1StateClass(IEventAggregator eventAggregator) : base(eventAggregator)
        {

        }
        public Button1StateClass()
        {

        }
        }
        public class Button2StateClass : IItem
        {
              public VisibilityStates Visibility { get => VisibilityStates.Button2; }
              [Browsable(true)]
              [Display(Order = 2, Name = "Object2", GroupName = "Objects", ResourceType typeof(Resources.DisplayNames), AutoGenerateField = true)]

             public ButtonViewModel Button2 { get; set; }
 public Button2StateClass(IEventAggregator eventAggregator) : base(eventAggregator)
        {

        }
        public Button2StateClass()
        {

        }
        }

【讨论】:

  • 这看起来很有希望,但我在 returnInstances.Add((Interface)Activator.CreateInstance(x)); command ,它说 MissingMethodException,来自 System.Reflection.TargetInvocationException。另外,returnInstances.Count = 0 和 foundTypes.Count = 2。returnInstances 应该是 0 吗?
  • 您在 Button1StateClass 类中使用了一些构造函数吗?它应该没有使用反射创建的参数。异常意味着构造函数的问题。
  • 是的,你说得对,我使用构造函数来继承 IEventAggregator ,就像public Button1(IEventAggregator eventAggregator) : base(eventAggregator) 一样,当我也更改它时public Button1() 它起作用了。还有其他方法可以继承 eventAggregator 吗?
  • 您可以将参数发送到实例激活器(我已经调整了将 IEventAggregator 参数添加到构造函数的帖子。
  • 它需要在这里和那里进行一些调整(因为显然我有一些其他类“继承”我的 Button1,所以我不得不为 Button2 做一些调整)但它终于起作用了!非常感谢,你应该得到所有的支持!
猜你喜欢
  • 1970-01-01
  • 2010-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多