我试图在DataGridView和为DGV提供数据的BindingList之间实现双向绑定。有些列还没有反映底层列表中的更改,我认为这是因为我没有提供属性设置器来通知属性更改。而不是代码设置的行属性相同的方式,我为进程属性,我试图得到更多的"优雅",我意识到我卡住....
我偶然发现了一篇非常有趣的关于更优雅的方法的文章,我正在尝试实现它的概念(请参阅):http://www.gavaghan.org/blog/2007/07/17/use-inotifypropertychanged-with-bindinglist/
以下是我想在我的CBMI中使用的Mike文章中的代码(建立为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执行并返回,这是一个作者遗漏,这应该返回真,因为方法想要一个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));
}
}
}
这个类的第二个属性的setter是我尝试使用Mike的静态方法的地方:
Utilities.Set(this, "Rows", ref rowsReturned, value, PropertyChanged);
如果我删除实用程序。按如下方式设置并编写代码:
Set(this, "Rows", ref rowsReturned, value, PropertyChanged);
. .然后我得到编译器抱怨"名称'Set'不存在于当前上下文中"。
我尝试使用公用程序添加;指令,但这并没有解决问题。
最后,我不理解参数:ref T oldValue, T newValue
也不是调用Set方法的参数value。
有人能帮我解决这些关于这段代码的多重困惑,这样我就可以使用这些更高级的想法了吗?
---- EDIT UPDATE ----两个好的答案帮助我实现了这个目标。上面原始帖子中的"第二个问题"仍然有点难以捉摸。为每个请求添加了关于如何打包的"最佳实践"的注释,以便我可以像Mike的原始文章中那样使用简单的调用语法。也就是说,我试图仅通过方法名称调用"helper"静态方法。我想了解如何调用:
set
{
Set(this, "Rows", ref rowsReturned, value, PropertyChanged);
}
而不是编码为:
set
{
Utilities.Set(this, "Rows", ref rowsReturned, value, PropertyChanged);
}
我通过编写实用程序得到了这个工作。但我猜这个问题有点变成- "我把静态方法放在哪里,如何调用它们,所以我不必用类名"限定"它们?"我想了解如何包装通常有用的"实用程序"类型的方法,不需要对象的实例。在本例中,静态方法名为Set,但我希望能够添加其他静态方法,例如:
public static int HelpfulMethodXXXX(string s, int num)
我有一个单独编译的DLL (Vstudio项目)只包含类文件。最终,我想我可以在其他应用程序中使用这个类。
声明这类静态方法的最佳位置是:
int i = HelpfulMethodXXXX("Sample", testNumber);
代替:
int i = ContainingClassName.HelpfulMethodXXXX("Sample", testNumber);
1:所有非void方法都需要有显式的返回语句。
2: CMBI。Common是命名空间。Utilities是类的名称。Set()是你的类的一个函数。
对Set()的调用只在Utilities类的上下文中有意义。Set()不是全局命名空间的一部分——因此,如果你想在Utilities类之外调用Set(),你必须指定你想要Utilities.Set(),而不是SomethingElse.Set()。(在Utilities内部,编译器理解Set()指的是Utilities.Set())。
Using语句只能包含名称空间(CMBI.Common),或者名称空间中的特定类,如果您不希望名称空间中的每个类(CMBI.Common. utilities)。但是,它们不能将类函数转换为全局函数。
3: T是该函数操作的泛型类型的名称。http://msdn.microsoft.com/en-us/library/ms379564 (v = vs.80) . aspx
泛型允许相同的代码操作整数集合和字符串集合,同时强制执行编译时类型安全(如果尝试将整数压入字符串集合,编译器将给出错误)
ref意味着形参作为引用传递——在函数体中对形参所做的更改将在函数调用者的上下文中传播到形参的值。
-
看起来返回类型应该从
bool
更改为void
,因为它似乎从来没有返回不同的值 -
是的,
Utilities.Set
是正确的语法。例如,Java中没有类似的静态导入,因此必须使用类来限定它。如果您选择的话,您可以使用扩展方法,并且可以调用像this.Set(...)
这样的方法。要做到这一点,只需在Set
方法的第一个参数前添加this
关键字:
,
public static bool Set<T>(this object owner, string propName,
ref T oldValue, T newValue, PropertyChangedEventHandler eventHandler)
ref T oldValue
意味着你可以传递给它一个T
类型的变量,它会将旧的值写入其中(换句话说,值类型的引用传递)。这样你就能知道oldValue
是什么了。(虽然在我看来out
参数会更有意义)T newValue
是您试图设置的新值。如果您要问T
是什么,它是一个泛型类型,并充当类型真正的占位符。它根据您传递给它的参数的类型自动计算出哪种类型。(如果你给它传递一个string
, T的行为就像你使用string
而不是T
一样)value
是c#中的一个特殊关键字,仅在您定义的属性的set
访问器中具有特殊含义。