我正在尝试在 DataGridView 和为 DGV 提供数据的 BindingList 之间实现双向绑定。有些列尚未反映基础列表中的更改,我认为这是因为我没有提供属性设置器来通知属性更改。我没有像为 Process 属性那样为 Rows 属性编写 setter 代码,而是试图变得更“优雅”,但我意识到我被困住了......
我偶然发现了一篇非常有趣的文章,提出了一种更优雅的方法,我正在尝试实现它的概念(请参阅): http ://www.gavaghan.org/blog/2007/07/17/use-inotifypropertychanged-与绑定列表/
这是我想使用的 Mike 文章中的代码(在我的 CBMI.Common 项目中建立为Utilities.cs ):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
namespace CBMI.Common
{
public static class Utilities
{
public static bool Set<T>(object owner, string propName,
ref T oldValue, T newValue, PropertyChangedEventHandler eventHandler)
{
// make sure the property name really exists
if (owner.GetType().GetProperty(propName) == null)
{
throw new ArgumentException("No property named '" + propName + "' on " + owner.GetType().FullName);
}
if (!Equals(oldValue, newValue)) // we only raise an event if the value has changed
{
oldValue = newValue;
if (eventHandler != null)
{
eventHandler(owner, new PropertyChangedEventArgs(propName));
}
}
return true; // Please NOTE: I had to add this statement to avoid compile error:
// "not all code paths return a value".
}
}
}
所以,我的第一个问题是:作者在他的文章中没有返回语句,我添加了它来解决编译器错误。我猜 eventHandler 执行并返回,这是作者的遗漏,这应该返回 true,因为该方法需要 bool 返回类型。这是正确的假设吗?
我的第二个问题显示了当我尝试使用上面的这个辅助方法时我是一个 C# 菜鸟。我已将此类编码到与上述相同的项目(和命名空间)中名为InputFileInfo.cs的单独文件中:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
namespace CBMI.Common
{
public class InputFileInfo : INotifyPropertyChanged
{
private bool processThisFile;
public bool Process
{
get { return processThisFile; }
set
{
processThisFile = value;
this.NotifyPropertyChanged("Process");
}
}
public string FileName { get; set; }
private long rowsReturned;
public long Rows
{
get { return rowsReturned; }
set
{
Utilities.Set(this, "Rows", ref rowsReturned, value, PropertyChanged);
}
}
public string Message { get; set; }
// constructor
public InputFileInfo(string fName)
{
Process = true;
FileName = fName;
Rows = 0;
Message = String.Empty;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
此类中第二个属性的设置器是我尝试使用 Mike 的静态方法的地方:
Utilities.Set(this, "Rows", ref rowsReturned, value, PropertyChanged);
如果我删除 Utilities.Set 并将其编码如下:
Set(this, "Rows", ref rowsReturned, value, PropertyChanged);
..然后我得到编译器抱怨“当前上下文中不存在名称'Set'”。
我尝试添加一个using Utilities;指令,但这并没有解决问题。
最后,我不明白参数:ref T oldValue,T newValue,也不是调用Set方法
的参数称为value 。
有人可以帮助我解决有关此代码的这些多重困惑,以便我可以使用这些更高级的想法吗?
---- 编辑更新---- 两个好的答案帮助我完成了这项工作。上面原始帖子中的“第二个问题”仍然有点难以捉摸。为每个请求关于如何打包它的“最佳实践”添加注释,以便我可以使用 Mike 原始文章中的简单调用语法。也就是说,我正在寻求仅通过方法名称来调用“帮助”静态方法。我想了解如何调用:
set
{
Set(this, "Rows", ref rowsReturned, value, PropertyChanged);
}
而不必编码为:
set
{
Utilities.Set(this, "Rows", ref rowsReturned, value, PropertyChanged);
}
我通过编写 Utilities.Set 得到了这个工作,但我猜这个问题有点变形 - “我在哪里放置静态方法以及如何调用它们,所以我不必用类名“限定”它们?我想了解如何打包不需要对象实例的通常有用的“实用程序”类型方法。在这种情况下,静态方法称为 Set 但我希望能够添加其他静态方法,例如:
public static int HelpfulMethodXXXX(string s, int num)
我有一个单独编译的 DLL(Vstudio 项目),只包含类文件。最终,我想我可以在其他应用程序中使用这个类。
声明这些静态方法的最佳位置在哪里,以便可以将它们调用为:
int i = HelpfulMethodXXXX("Sample", testNumber);
代替:
int i = ContainingClassName.HelpfulMethodXXXX("Sample", testNumber);