- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
这可能是一个微不足道的问题,但我在这里画了一个空白,似乎无法在网上找到答案。
基本上,我正在尝试创建一个方法,该方法将属于 INotifyPropertyChanged
类的 2 个属性作为参数(要在反射中使用的实际属性,而不是属性值),并保持它们像绑定(bind)一样“同步”。
我有一个名为 Student
的类,它有一个名为 int SemesterScore
的属性。我有另一个名为 Semester
的类(class),它有一个名为 int Score
的属性。这两个类都实现了 IPropertyNotifyChanged
。
现在,让我们暂时假设我们不能扩展任何类(就像在我的现实生活场景中一样)并且我可能在不同的类中多次想要使用它。
基本上,我希望能够在我的一个类中调用一个方法,将两个属性“链接”在一起。也就是说,如果其中一个发生更改,它将自动更新另一个。
在非工作代码中,这是基本概念:
public class Student : INotifyPropertyChanged
{
private int _semesterScore;
public int SemeseterScore
{
get { return _semesterScore; }
set { [ set property stuff with property changed] }
}
}
public class Semester: INotifyPropertyChanged
{
private int _score;
public int Score
{
get { return _score; }
set { [ set property stuff with property changed] }
}
}
public class Entry
{
public static void Main(string[] args)
{
Student student = new Student();
Semester semester = new Semester();
AttachProperties(student.SemesterScore, semester.Score); // This obviously won't work, but this is where I pass the properties in
semester.Score = 7;
Console.WriteLine(student.SemesterScore); // Output will be 7
}
public static void AttachProperties([sometype] prop1, [sometype] prop2)
{
// Sudo code
prop1.classInstance.PropertyChanged += (pe)
{
if (pe.Property == prop1.Name)
prop2.Value = prop1.Value;
}
prop2.classInstance.PropertyChanged += (pe)
{
if (pe.Property == prop2.Name)
prop1.Value = prop2.Value;
}
}
}
有什么办法吗?我知道一些解决方法(也就是传递 INotifyPropertyChanged 类和属性名称,然后进行一些反射(reflection)以使其起作用),但是在我的编码中出现了几次传递属性实例(并用它做事)的问题事业。
最佳答案
一种方法是使用 Observable
,就像上面建议的@itay-podhacer。
但是如果你只想使用反射和 INotifyPropertyChanged
来实现这是您可以做到的。
首先,让我们得到 SemesterScore
和 Student
两者都实现 INotifyPropertyChanged
:
public class Student : INotifyPropertyChanged
{
private int semesterScore;
public int SemesterScore
{
get { return semesterScore; }
set
{
semesterScore = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Semester : INotifyPropertyChanged
{
private int score;
public int Score
{
get { return score; }
set
{
score = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
现在让我们将这些属性联系在一起,在您的 AttachProperties
中辅助方法。为此,我们将使 AttachProperties 方法采用 Expression<Func<T,object>
。参数,这样我们就可以避免传递魔术字符串,并可以使用反射来检索属性名称。
顺便说一句,要在生产环境中运行它,您可能需要记住该反射代码以提高性能。
private static void AttachProperties<T1,T2>(Expression<Func<T1, object>> property1, T1 instance1, Expression<Func<T2, object>> property2, T2 instance2)
where T1 : INotifyPropertyChanged
where T2 : INotifyPropertyChanged
{
var p1 = property1.GetPropertyInfo();
var p2 = property2.GetPropertyInfo();
//A NULL or empty PropertyName in PropertyChangeEventArgs means that all properties changed
//See: https://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.propertychanged(v=vs.110).aspx#Anchor_1
((INotifyPropertyChanged)instance1).PropertyChanged += (_, e) =>
{
if (e.PropertyName == p1.Name || string.IsNullOrEmpty(e.PropertyName))
{
SyncProperties(p1, p2, instance1, instance2);
}
};
((INotifyPropertyChanged)instance2).PropertyChanged += (_, e) =>
{
if (e.PropertyName == p2.Name || string.IsNullOrEmpty(e.PropertyName))
{
SyncProperties(p2, p1, instance2, instance1);
}
};
}
private static void SyncProperties(PropertyInfo sourceProperty, PropertyInfo targetProperty, object sourceInstance, object targetInstance)
{
var sourceValue = sourceProperty.GetValue(sourceInstance);
var targetValue = targetProperty.GetValue(targetInstance);
if (!sourceValue.Equals(targetValue))
{
targetProperty.SetValue(targetInstance, sourceValue);
}
}
最后,这是检索 PropertyInfo
的反射代码从参数:
public static class ReflectionExtension
{
public static PropertyInfo GetPropertyInfo<T>(this Expression<Func<T, object>> expression)
{
var memberExpression = GetMemberExpression(expression);
return (PropertyInfo)memberExpression.Member;
}
private static MemberExpression GetMemberExpression<TModel, T>(Expression<Func<TModel, T>> expression)
{
MemberExpression memberExpression = null;
if (expression.Body.NodeType == ExpressionType.Convert)
{
var body = (UnaryExpression)expression.Body;
memberExpression = body.Operand as MemberExpression;
}
else if (expression.Body.NodeType == ExpressionType.MemberAccess)
{
memberExpression = expression.Body as MemberExpression;
}
if (memberExpression == null)
{
throw new ArgumentException("Not a member access", "expression");
}
return memberExpression;
}
}
有了这一切,您现在可以保持两个属性同步:
public class PropertySyncTests
{
public void Should_sync_properties()
{
var semester = new Semester();
var student = new Student();
AttachProperties(x => x.Score, semester, x => x.SemesterScore, student);
semester.Score = 7;
student.SemesterScore.ShouldBe(7);
}
}
关于c# - 传递属性并上课,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38382410/
你能比较一下属性吗 我想禁用文本框“txtName”。有两种方式 使用javascript,txtName.disabled = true 使用 ASP.NET, 哪种方法更好,为什么? 最佳答案 我
Count 属性 返回一个集合或 Dictionary 对象包含的项目数。只读。 object.Count object 可以是“应用于”列表中列出的任何集合或对
CompareMode 属性 设置并返回在 Dictionary 对象中比较字符串关键字的比较模式。 object.CompareMode[ = compare] 参数
Column 属性 只读属性,返回 TextStream 文件中当前字符位置的列号。 object.Column object 通常是 TextStream 对象的名称。
AvailableSpace 属性 返回指定的驱动器或网络共享对于用户的可用空间大小。 object.AvailableSpace object 应为 Drive 
Attributes 属性 设置或返回文件或文件夹的属性。可读写或只读(与属性有关)。 object.Attributes [= newattributes] 参数 object
AtEndOfStream 属性 如果文件指针位于 TextStream 文件末,则返回 True;否则如果不为只读则返回 False。 object.A
AtEndOfLine 属性 TextStream 文件中,如果文件指针指向行末标记,就返回 True;否则如果不是只读则返回 False。 object.AtEn
RootFolder 属性 返回一个 Folder 对象,表示指定驱动器的根文件夹。只读。 object.RootFolder object 应为 Dr
Path 属性 返回指定文件、文件夹或驱动器的路径。 object.Path object 应为 File、Folder 或 Drive 对象的名称。 说明 对于驱动器,路径不包含根目录。
ParentFolder 属性 返回指定文件或文件夹的父文件夹。只读。 object.ParentFolder object 应为 File 或 Folder 对象的名称。 说明 以下代码
Name 属性 设置或返回指定的文件或文件夹的名称。可读写。 object.Name [= newname] 参数 object 必选项。应为 File 或&
Line 属性 只读属性,返回 TextStream 文件中的当前行号。 object.Line object 通常是 TextStream 对象的名称。 说明 文件刚
Key 属性 在 Dictionary 对象中设置 key。 object.Key(key) = newkey 参数 object 必选项。通常是 Dictionary 
Item 属性 设置或返回 Dictionary 对象中指定的 key 对应的 item,或返回集合中基于指定的 key 的&
IsRootFolder 属性 如果指定的文件夹是根文件夹,返回 True;否则返回 False。 object.IsRootFolder object 应为&n
IsReady 属性 如果指定的驱动器就绪,返回 True;否则返回 False。 object.IsReady object 应为 Drive&nbs
FreeSpace 属性 返回指定的驱动器或网络共享对于用户的可用空间大小。只读。 object.FreeSpace object 应为 Drive 对象的名称。
FileSystem 属性 返回指定的驱动器使用的文件系统的类型。 object.FileSystem object 应为 Drive 对象的名称。 说明 可
Files 属性 返回由指定文件夹中所有 File 对象(包括隐藏文件和系统文件)组成的 Files 集合。 object.Files object&n
我是一名优秀的程序员,十分优秀!