1

編集:正しい軌道に乗ったので、答えをマークしました。残っている唯一の問題は設計上の問題のようであり、ボードルールによれば、別の質問として尋ねるべきです。ここで私のフォローアップの質問を参照してください: https://stackoverflow.com/questions/19744475/design-issue-how-to-approach-this-specific-task

カスタム オブジェクトのリストを DataGrid にバインドしようとしています。ストレート バインドは簡単に思えますが、クラスに直接表示されない追加のフィールドに複雑な数式を指定する必要があります。また、グリッド内のデータを編集して、関連するフィールドの更新を取得できるようにしたいと考えています。説明するのが本当に難しいので、例を示しましょう。アイテムのある部屋に単純化します。各アイテムは赤と青にすることができます。

私のクラスは次のようになります。

public class room
{
   public string strRoomName { set; get; }
   public string strItemname { set; get; }
   public int intRedItem { set; get; }
   public int intBlueItem { set; get; }
}

今、dataTable.ItemSource = myList; を使用すると、私はこのようなものを得る:

nr. | room | name | red | blue

1. living room, ball, 2, 1
2. sleeping room, bunny, 4, 1
3. living room, chair, 3, 2
4. kitchen, ball, 4, 7
5. garage, chair, 1, 4

複雑な部分については、助けが必要です。すべてのアイテムを赤と青の同じ数字にしたい。そして、これは当てはまらないため、部屋ごとの「不均衡」と、次のようにグローバルに見たいと思います。

nr. | room | name | red | blue | missing | global red | global blue | global missing 

1. living room, ball, 2, 1, 1 blue, 6, 7, 1 red
2. sleeping room, bunny, 4, 1, 3 blue, 4, 1, 3 blue
3. living room, chair, 3, 2, 1 blue, 4, 6, 2 red 
4. kitchen, ball, 4, 7, 3 red, 6, 7, 1 red
5. garage, chair, 1, 4, 3 red, 4, 6, 2 red

ご覧のとおり、これは Excel の数式のように見えますが、C# コードでこれを処理する方法がわかりません。また、同じ行のデータを使用する必要があることもわかりますが、1 つのプロパティ (アイテム名) に一致する他の行からデータを取得することもできます。

また、1行目の青い値= 1を値= 2に変更すると、1行目が次のようになります。

1. living room, ball, 2, 2, even, 6, 8, 2 red

および大まかな行 4 を次のように変更する必要があります。

4. kitchen, ball, 4, 7, 3 red, 6, 8, 2 red

編集:あなたの答えを読み、ヒントを実装するスキルをテストした後、クラスとして次のコードを作成しました:

public class RoomList : ObservableCollection<room>
{
    public RoomList() : base()
    {
        Add(new room() { strRoomName = "living room", strItemname = "ball", intRedItem = 2, intBlueItem = 1 });
        Add(new room() { strRoomName = "sleeping room", strItemname = "bunny", intRedItem = 4, intBlueItem = 1 });
        Add(new room() { strRoomName = "living room", strItemname = "chair", intRedItem = 3, intBlueItem = 2 });
        Add(new room() { strRoomName = "kitchen", strItemname = "ball", intRedItem = 4, intBlueItem = 7 });
        Add(new room() { strRoomName = "garage", strItemname = "chair", intRedItem = 1, intBlueItem = 4 });
    }
}
//rooms
public class room : INotifyPropertyChanged
{
    public string strRoomName { set; get; }
    public string strItemname { set; get; }
    private int _intRed = 0;
    private int _intBlue = 0;
    public int intRedItem
    {
        get { return _intRed; }
        set
        {
            _intRed = value;
            NotifyPropertyChanged("intRedItem", "strMissing");
        }
    }
    public int intBlueItem
    {
        get { return _intBlue; }
        set
        {
            _intBlue = value;
            NotifyPropertyChanged("intBlueItem", "strMissing");
        }
    }
    public string strMissing
    {
        get
        {
            int missingCount = intRedItem - intBlueItem;
            return missingCount == 0 ? "Even" : missingCount.ToString();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanged(params string[] propertyNames)
    {
        if (PropertyChanged != null)
        {
            foreach (string propertyName in propertyNames)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

編集 1:「不足している」フィールドがすぐに機能するようになりました。そのヒントに感謝します。想像していたほど簡単で、将来のプロジェクトに大いに役立ちます。

Edit2: クラスにプライベート ダミー変数を追加して StackOverflow-Error を修正しました。上記のコードを参照してください。

Edit3:リソースも修正しました。昨日まったく同じコードを使用したことを誓っていますが、現在は機能しています。しかたがない。

唯一の本当の問題が残っています:

他のオブジェクトのプロパティに基づいてプロパティを設定するにはどうすればよいですか? 「globalRed」プロパティは、リストまたはコレクションをループする必要がありますが、どちらもオプションではないようです。少なくとも、私は通常これをコードで行うようではありません。「listRooms」はプロパティ ゲッターに表示されません。また、新しいオブジェクトが追加された後、これを再度ループする必要があります。otify メソッドもこれを処理すると思いますが、そもそもループするにはどうすればよいですか?

そして、理解を深めるためにもう 1 つ質問します。

上記のコレクションがリストアプローチよりも好ましい理由を簡単に説明できる人はいますか? 私がテストできた限り、それらは同じように動作します。

//the list-Way
datagridRooms.ItemsSource = listRooms.Where(x=>x.strRoomName == "living room");
//indentical with the collection-way...
datagridRooms.ItemsSource = new RoomList().Where(x=>x.strRoomName== "living room");
4

2 に答える 2

1

クラスに直接表示されない追加のフィールド。

既存のクラスにこれ以上プロパティを追加できない場合、あなたができる最善の方法の 1 つは、言及したプライマリ クラスからPartialクラスを作成することです。そこで、他の列のロジックをプロパティとして追加し、プロパティのゲッター/セッター内にビジネス ロジックを配置して、前述のExcelタイプの操作を処理できます。

部分クラスが利用できない場合は、元のクラスを継承し、必要な拡張プロパティを実装するクラスを作成します。元のクラスが封印されていない限り、それを防ぎます。

完了したら、新しく変更されたクラスを使用してグリッドに表示できます。

また、グリッド内のデータを編集して、関連するフィールドの更新を取得できるようにしたいと考えています。

クラスをINotifyPropertyChangedに準拠させる必要があります。これにより、変更が発生し、直接関与しなくても画面に表示されます。

私のクラスを構成するためのより良い方法。

基本的な MVVM (モデル、ビュー、ビュー-モデル アプローチ) を実行します。これは、画面ロジックから離れてデータを整理するための単なる方法です。

ビューは、グリッドを保持し、GUI に関連するイベントを処理するページです。ViewModel はデータの取得を担当し、率直に言って、View によってバインドされるデータを保持するだけです。そこにアイテムのリストを配置し、それをObservable Collectionに配置する必要があります。これは、リストからアイテムを削除したり、GUI に通知を送信したりするときに役立ちます (そのようなイベントを購読したい場合)。M はモデルであり、それは先ほど述べたクラスです。Xaml: ViewModel Main Page Instantiation and Loading Strategy for Easier Bindingというタイトルの私のブログ記事で、VM とビューを示す基本的な例を提供しています。

注目すべきインターフェース

C#インターフェイスの観点からクラス インスタンスを定義する習慣を身につけてください。インターフェイスを特定のタスクを実行するためのコントラクトと見なすと、それ自体が開発の一貫性を提供し、非常に拡張可能なコードにつながります。インターフェイスを使用すると、さまざまなオブジェクトを 1 つのリストにまとめ一貫した方法で処理できます。クラスやインスタンスだけでなく、より高いレベルの理解でコードを考えるという点で非常に強力です。これにより、より多くの機能を追加してコードをテスト可能にすることができます ( Visual Studio での単体テストを参照)。インターフェイスを使用するには事前に多くの作業が必要ですが、将来的には成果が得られるため、今後 C# を学習する際に検討する必要があります。

于 2013-11-02T02:58:35.117 に答える