DataGridViewとDGVにデータを提供するBindingListの間で双方向のバインディングを実現しようとしています。一部の列は、基になるリストの変更をまだ反映していません。これは、プロパティの変更を通知するためのプロパティセッターを提供していないためだと思います。Processプロパティの場合と同じようにRowsプロパティのセッターをコーディングするのではなく、より「エレガント」にしようとしていますが、行き詰まっていることに気づきました。
私はよりエレガントなアプローチのための非常に興味深い記事に出くわしました、そして私はそれの概念を実装しようとしています(参照してください): http ://www.gavaghan.org/blog/2007/07/17/use-inotifypropertychanged- with-bindinglist /
これが私が使いたいマイクの記事(私の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".
}
}
}
それで、これについての私の最初の質問:著者は彼の記事にreturnステートメントを持っていませんでした、そして私はコンパイラエラーを解決するそれを追加しました。eventHandlerが実行されて返されると思いますが、これは作成者の省略であり、メソッドがブール値の戻り型を必要とするため、これはtrueを返すはずです。それは正しい仮定ですか?
2番目の質問は、上記のヘルパーメソッドを使用しようとしたときの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));
}
}
}
このクラスの2番目のプロパティのセッターは、Mikeの静的メソッドを使用しようとする場所です。
Utilities.Set(this, "Rows", ref rowsReturned, value, PropertyChanged);
Utilities.Setを削除し、次のようにコーディングした場合:
Set(this, "Rows", ref rowsReturned, value, PropertyChanged);
..次に、 「名前'Set'は現在のコンテキストに存在しません」とコンパイラが文句を言います。
ユーティリティを使用して追加してみました。ディレクティブですが、問題は解決しませんでした。
最後に、私はパラメーターを理解していません:ref T oldValue、T newValue 、またはSetメソッドが呼び出されるvalue
と呼ばれるパラメーター。
私がこれらのより高度なアイデアを使用できるように、誰かがこのコードに関するこれらの複数の混乱について私を助けてくれますか?
----更新の編集---- 2つの良い答えが、これを機能させるのに役立ちました。上記の元の投稿の「2番目の質問」は、少しわかりにくいままです。マイクの元の記事のように単純な呼び出し構文を使用できるように、これをパッケージ化する方法に関する「ベストプラクティス」を要求するそれぞれにコメントを追加しました。つまり、メソッド名のみで「ヘルパー」静的メソッドを呼び出そうとしています。次のように呼び出す方法を理解したい:
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);