【问题标题】:WPF databinding to composite class patterns?WPF 数据绑定到复合类模式?
【发布时间】:2009-07-29 15:05:31
【问题描述】:

我是第一次尝试 WPF,我正在努力解决如何将控件绑定到使用其他对象的组合构建的类。例如,如果我有一个由两个单独的类组成的 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;
...

或者我是否正在重塑 M-V-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;
...

那我应该怎么做呢?如果它是第一个或第三个模式,那么我似乎已经获取了我所有可爱的(不同的)层次结构数据并将其分解为一个平面配置,以便我可以将它绑定到 UI 元素。这是它必须发生的方式,还是有更好的方法(第二种模式??)

编辑

我没有想到我真的想要双向绑定。所以属性访问器确实应该有 get 和 set。

编辑

更新了我的伪代码以显示 setter 和 getter

编辑

我遵循了 Mark 和 Julien 提供的模式并实现了 setter,并对结果感到满意。出于某种原因,我说服自己,属性的设置不会一直跟随到最终实体。

【问题讨论】:

  • 这正是我所坚持的!谢谢:)

标签: c# wpf data-binding object composite


【解决方案1】:

数据绑定通过属性工作,因此您不会在绑定中使用任何成员变量,例如:

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 被赋予了 Comp 作为 DataContext(因此它的所有子级也具有该 DataContext,除非指定了另一个),并且文本绑定到它的成员类。

编辑:我还添加了 setter 并实现了 INotifyPropertyChanged,这是数据绑定的重要组成部分。实现此功能后,您将能够将数据绑定到多个控件,并在更新时查看所有控件中的数据更新。您需要添加: 使用 System.ComponentModel;

【讨论】:

  • 好的,我可以看到.. 但是(我必须编辑我的问题).. 这对双向绑定有何影响? “二传手”会是什么样子?
  • 彼得,我添加了二传手,尽管我注意到您已经将这些添加到您的问题中。我还实现了 INotifyPropertyChanged,因此您可以绑定到多个控件并保持它们同步。
【解决方案2】:

我认为你总是必须绑定到一个属性,所以你的类应该是:

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}" />    
....

【讨论】:

  • 脖子和脖子与标记答案。但获胜者将取决于问题的答案——我如何使用两种方式绑定来设置相同的属性? :D
  • 如果您使用允许编辑的控件,绑定会自动双向。 TextBlock 是一个只读控件。尝试一个文本框,看看你得到了什么。此外,您在这里缺少 INotifyPropertyChanged 实现。您将需要它,以便您的控件知道您的属性何时更改。事实上,看起来你真的正在转向 MVVM。为了朝着正确的方向前进,请尝试使用mvvmfoundation.codeplex.com 的 MVVMFoundation 内容。这将帮助您处理通常带有适当 MVVM 的大量管道代码。
  • @Anderson 我留下了很多东西,比如 INotifyPropertyChanged 来尝试减少帖子的物理大小。我已经按照 Julien 和 Mark 实施了一个测试程序——它也实施了 setter,我对此很满意。但我会看看你发布的 MVVM 链接。谢谢。
猜你喜欢
  • 2018-12-16
  • 1970-01-01
  • 2012-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-07
  • 2016-10-07
  • 2013-02-05
相关资源
最近更新 更多