1

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);
4

2 に答える 2

1

1:すべての非voidメソッドには、明示的なreturnステートメントが必要です。

2:CMBI.Commonは名前空間です。ユーティリティはクラスの名前です。Set()はクラスの関数です。

Set()の呼び出しは、Utilitiesクラスのコンテキストでのみ意味があります。Set()はグローバル名前空間の一部ではありません。そのため、Utilitiesクラスの外部でSet()を呼び出す場合は、SomethingElse.Set()ではなくUtilities.Set()が必要であることを指定する必要があります。 。(Utilities内では、コンパイラはSet()がUtilities.Set()を参照していることを理解します)。

ステートメントの使用には、名前空間(CMBI.Common)、または名前空間内のすべてのクラス(CMBI.Common.Utilities)が必要ない場合は、名前空間内の特定のクラスのみを含めることができます。ただし、クラス関数をグローバル関数に変換することはできません。

3:Tは、この関数が動作するジェネリック型の名前を指します。http://msdn.microsoft.com/en-us/library/ms379564(v=vs.80).aspx

ジェネリックスを使用すると、同じコードで整数のコレクションや文字列のコレクションを操作しながら、コンパイル時の型の安全性を確保できます(整数を文字列のコレクションにプッシュしようとすると、コンパイラはエラーになります)。

refは、パラメーターが参照として渡されることを意味します。関数の本体内でパラメーターに加えられた変更は、関数の呼び出し元のコンテキストでパラメーターの値に伝播されます。

于 2011-07-20T22:20:26.600 に答える
1
  • 異なる値を返すようには見えないため、戻りタイプをからに変更する必要があるようboolです。void

  • はい、Utilities.Set正しい構文です。たとえば、Javaには静的インポートに類似したものがないため、クラスで修飾する必要があります。必要に応じて拡張メソッドを使用し、代わりthis.Set(...)にのようにメソッドを呼び出すことができます。これを行うには、メソッドthisの最初のパラメーターの前にキーワードを追加するだけです。Set

 

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にあるかどうかのプレースホルダーとして機能します。渡された引数のタイプに基づいて、どのタイプが自動的に判別されます。(これを渡すと、Tは代わりに使用した場合とまったく同じように機能します。)stringstringT

  • valueは、C#の特別なキーワードであり、set定義したプロパティのアクセサーでのみ特別な意味を持ちます。これは、プロパティに割り当てようとしている値です。

于 2011-07-20T22:24:59.640 に答える