5

初めて WPF を試していますが、他のオブジェクトの構成を使用して構築されたクラスにコントロールをバインドする方法に苦労しています。たとえば、2 つの別個のクラスで構成されるクラス Comp があるとします (わかりやすくするために、さまざまな要素が省略されていることに注意してください)。

class One {
   int _first;
   int _second;
}

class Two {
   string _third;
   string _fourth;
}

class Comp {
   int _int1;
   One _part1;
   Two _part2;
}

これで、Comp で定義された「get」を使用して _int1 を簡単にバインドできることがわかりました。しかし、要素 _part1._first、_part1._second にバインドするにはどうすればよいですか。クラス Comp レベルで「ゲッター」を公開していますか? または、複合クラス内でそれらを公開し、それらを指すバインディング パスを使用できますか? そして、これはプロパティの設定でどのように機能しますか?

ということで、これがパターン?

....
<TextBlock Name="txtBlock" Text="{Binding Path=Third}" />    
....

class One {
   int _first;
   int _second;
}

class Two {
   string _third;
   string _fourth;
}

class Comp {
   int _int1;
   One _part1;
   Two _part2;

   int Int1 { get { return _int1; } set { _int1 = value; } }
   int First { get { return _part1._first; }  set { _part1._first = value; } }
   int Second { get { return _part1._second; } set { _part1._second = value; } }
   string Third { get { return _part2._third; }  set { _part2._third = value; } }
   string Fourth { get { return _part2.fourth; }  set { _part2._fourth = value; } }
}

...
Comp oComp = new Comp();
txtBlock.DataContext = oComp;
...

それともこのパターン?(パスに何を入れればよいかわからない場合)

....
<TextBlock Name="txtBlock" Text="{Binding Path=_part2.Third}" />    
....

class One {
   int _first;
   int _second;
   int First { get { return _first; }  set { _first = value; } }
   int Second { get { return _second; }  set { _second = value; } }
}

class Two {
   string _third;
   string _fourth;
   string Third { get { return _third; } set { _third = value; } }
   string Fourth { get { return _fourth; } set { _fourth = value; } }
}

class Comp {
   int _int1;
   One _part1;
   Two _part2;

   int Int1 { get { return _int1; } }
}

...
Comp oComp = new Comp();
txtBlock.DataContext = oComp;
...

それとも、MV-VM を再発明しようとしているのですか (ゆっくりと理解し始めています)。

....
<TextBlock Name="txtBlock" Text="{Binding Path=Third}" />    
....

class One {
   int _first;
   int _second;
}

class Two {
   string _third;
   string _fourth;
}

class Comp {
   int _int1;
   One _part1;
   Two _part2;

}

class CompView {
   Comp _comp;

   CompView( Comp comp ) {
      _comp = comp;
   }

   int Int1 { get { return _comp._int1; } set { _comp._int1 = value; } }
   int First { get { return _comp._part1._first; }  set { _comp._part1._first = value; } }
   int Second { get { return _comp._part1._second; } set { _comp._part1._second = value; } }
   string Third { get { return _comp._part2._third; }  set { _comp._part2._third = value; } }
   string Fourth { get { return _comp._part2.fourth; }  set { _comp._part2._fourth = value; } }
 }

...
Comp oComp = new Comp();
CompView oCompView = new CompView( oComp );
txtBlock.DataContext = oCompView;
...

では、どうすればよいのでしょうか。それが最初または 3 番目のパターンである場合、UI 要素にバインドできるように、素敵な (異種の) 階層データをすべて取り込んでフラットな構成にまとめたようです。これはどうあるべきか、それとももっと良い方法がありますか (2 番目のパターン??)

編集

私は本当に双方向バインディングが欲しいという質問を省きました。そのため、プロパティ アクセサーは本当に get と set を持つ必要があります。

編集

セッターとゲッターを表示するように擬似コードを更新しました

編集

Mark と Julien によって提供されたパターンに従い、セッターを実装したところ、結果に満足しました。何らかの理由で、プロパティの設定が最終的なエンティティまでずっと続くわけではないことを確信しました。

4

2 に答える 2

4

データバインディングはプロパティを介して機能するため、バインディングでメンバー変数を使用することはありません。例:

int _first
public int First { get { return _first; } }

バインディングには_firstではなくFirstを使用します。通常、各クラスがバインドする独自のプロパティを提供しているのを見てきました。その場合、コードを次のように変更できます。

class One : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string property)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    }

    int _first = 1;
    int _second = 2;
    public int First { get { return _first; }
                       set { _first = value; OnPropertyChanged("First"); } }
    public int Second { get { return _second; }
                        set { _second = value; OnPropertyChanged("Second"); } }
}

class Two : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string property)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    }

    string _third = "Third";
    string _fourth = "Fourth";
    public string Third { get { return _third; }
                          set { _third = value; OnPropertyChanged("Third"); } }
    public string Fourth { get { return _fourth; }
                           set { _fourth = value; OnPropertyChanged("Fourth"); } }
}

class Comp : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string property)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    }

    int _int1 = 100;
    One _part1 = new One();
    Two _part2 = new Two();

    public One Part1 { get { return _part1; }
                       set { _part1 = value; OnPropertyChanged("Part1"); } }
    public Two Part2 { get { return _part2; }
                       set { _part2 = value; OnPropertyChanged("Part2"); } }

    public int Int1 { get { return _int1; }
                      set { _int1 = value; OnPropertyChanged("Int1"); } }
}

フィールドをデフォルトでプライベートにしたまま、プロパティをパブリックにしたことに注意してください。親コントロールのDataContextをCompのインスタンスに割り当てる場合:

Comp comp = new Comp();
stack.DataContext = comp;

次に、次のようにxamlのピースにバインドできます。

<Window x:Class="TestApp.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TestApp"
    Title="Window1" Height="300" Width="300">
    <StackPanel Name="stack">
        <TextBlock Text="{Binding Int1}"/>
        <TextBlock Text="{Binding Part1.First}"/>
        <TextBlock Text="{Binding Part1.Second}"/>
        <TextBlock Text="{Binding Part2.Third}"/>
        <TextBlock Text="{Binding Part2.Fourth}"/>
    </StackPanel>
</Window>

ここでは、StackPanelにDataContextとしてCompが与えられ(したがって、別の子が指定されていない限り、そのすべての子にもそのDataContextがあります)、テキストはそのメンバークラスにバインドされます。

編集:セッターを追加し、データバインディングに不可欠なコンポーネントであるINotifyPropertyChangedを実装しました。これを実装すると、データを複数のコントロールにバインドし、更新時にすべてのコントロールでデータの更新を確認できるようになります。追加する必要があります:using System.ComponentModel;

于 2009-07-29T15:27:05.507 に答える
1

常にプロパティにバインドする必要があると思うので、クラスは次のようにする必要があります。

class One {
  int _first;
  int _second;
  int First { get { return _first; } }
  int Second { get { return _second; } }
}

class Two {
  string _third;
  string _fourth;
  string Third { get { return _third; } }
  string Fourth { get { return fourth; } }
}

class Comp {
  int _int1;
  One _part1;
  Two _part2;
  One Part1 { get { return _part1; } }
  Two Part2 { get { return _part2; } }
}

次に、必要なものにバインドできるはずです。

....
<TextBlock Name="txtBlock" Text="{Binding Path=Part2.Third}" />    
....
于 2009-07-29T15:24:16.837 に答える