确定 属性 更改的内容,并编辑所有选定的项目

identify what property changed, and edit all selected Items

我最近发现如何在我的 ListView 中更改 属性 项时添加事件:

foreach (Profil item in gp.ListProfils)
{
    if (item is INotifyPropertyChanged)
    {
        INotifyPropertyChanged observable = (INotifyPropertyChanged)item;
        observable.PropertyChanged +=
            new PropertyChangedEventHandler(ItemPropertyChanged);
    }
}

现在,我想将修改应用于所有选定的项目。

我发现如何识别 属性 的名称已更改:

private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if(sender is Profil)
    {
        string myPropertyName = e.PropertyName;
        Profil editedProfile = (Profil)sender;
        foreach(Profil prf in this.SelectedProfiles)
        {
            //prf.NAME_PROPERTY = editedProfile.NAME_PROPERTY
            if (!this.ListProfilToEdit.Contains(editedProfile))
            {
                this.ListProfilToEdit.Add(editedProfile);
            }
        }
    }
}

但是我如何替换评论中的行。 具体来说,如果我编辑了“宽度”字段,我想更改所有选定元素的宽度。 有没有办法做到这一点,而无需创建单独的函数 EditProperty(string nameProperty)?

Is there a way to do it, without creating a separated function EditProperty(string nameProperty)?

是否创建一个单独的方法是一个好的设计和干净的代码的问题,它不会以任何方式影响问题的核心。您始终可以创建单独的方法或在现有方法中编写代码。

But how can I replace the line in comment.

不太清楚你在做什么,所以我怀疑你问的问题是否可以用不同的方式解决,但事实上,你要求只知道读写实例的属性他们的名字。您将需要为此使用 Reflection

For performing late binding, accessing methods on types created at run time. See the topic Dynamically Loading and Using Types.

假设您的属性是 public,这应该有效:

var propertyInfo = typeof(Profil).GetProperty(myPropertyName);
var value = propertyInfo.GetValue(editedProfile, null);

foreach(Profil prf in this.SelectedProfiles)
{
   propertyInfo.SetValue(prf, value);
   
   // ...other code.
}

也就是说,小心使用反射,进一步阅读:

这里需要能够从一个对象中动态读取一个属性,然后在另一个对象上动态写入。

您可以使用表达式树动态生成 Getters 和 Setters 并将它们放入缓存中。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace CoreAppMain
{
    public class TypeAccessors<T> where T : class
    {
        //Getters
        public static Dictionary<string, Func<T, object>> Getters = GetTypeGetters();

        private static Dictionary<string, Func<T, object>> GetTypeGetters()
        {
            var _getters = new Dictionary<string, Func<T, object>>();
            var props = typeof(T).GetProperties();
            foreach (var p in props)
            {
                var entityParam = Expression.Parameter(typeof(T), "e");
                Expression columnExpr = Expression.Property(entityParam, p);
                Expression conversion = Expression.Convert(columnExpr, typeof(object));
                var fct = Expression.Lambda<Func<T, object>>(conversion, entityParam).Compile();
                _getters.Add(p.Name, fct);
            }

            return _getters;
        }

        //setters
        public static Dictionary<string, Action<T, object>> Setters = GetTypeSetters();

        public static Dictionary<string, Action<T, object>> GetTypeSetters()
        {
            var setters = new Dictionary<string, Action<T, object>>();
            const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
            var propsToSet = typeof(T).GetProperties(flags)
                .Where(x => x.CanWrite)
                .ToList();

            foreach (var field in propsToSet)
            {
                var propertyInfo = typeof(T).GetProperty(field.Name);
                setters.Add(field.Name, GetPropertySetter<T>(propertyInfo));
            }
            return setters;
        }

        public static Action<TModel, object> GetPropertySetter<TModel>(PropertyInfo propertyInfo)
        {
            // Note that we are testing whether this is a value type
            bool isValueType = propertyInfo.DeclaringType.IsValueType;
            var method = propertyInfo.GetSetMethod(true);
            var obj = Expression.Parameter(typeof(object), "o");
            var value = Expression.Parameter(typeof(object));

            // Note that we are using Expression.Unbox for value types
            // and Expression.Convert for reference types
            Expression<Action<TModel, object>> expr =
                Expression.Lambda<Action<TModel, object>>(
                    Expression.Call(
                        isValueType ?
                            Expression.Unbox(obj, method.DeclaringType) :
                            Expression.Convert(obj, method.DeclaringType),
                        method,
                        Expression.Convert(value, method.GetParameters()[0].ParameterType)),
                        obj, value);
            Action<TModel, object> action = expr.Compile();
            return action;
        }

    }
}

用法示例:

var cust1 = new Customer()
{
    FirstName = "TOTOT",
    LastName = "TITI"
};

var cust2 = new Customer()
{
    FirstName = "XXXXXX",
    LastName = "YYYYYY"
};

var value = TypeAccessors<Customer>.Getters[nameof(Customer.FirstName)](cust2);
TypeAccessors<Customer>.Setters[nameof(Customer.FirstName)](cust1, value);

Console.WriteLine(cust1.FirstName);
Console.ReadKey();