【问题标题】:Master-detail data binding主从数据绑定
【发布时间】:2014-09-22 03:36:15
【问题描述】:

我的应用中有两个模型:

class Line
{
    string line_id  { get; set; }
    string color { get; set; }
}

class Point 
{
    string point_id { get; set; }
    string line_id { get; set; }
    int weight { get; set; }
}

我有两个 ObservableCollection:

lines - ObservableCollection<Line>
points - ObservableCollection<Point>

我想显示两个列表框:第一个(外部)显示线条,第二个(内部)显示属于这条线的点。

<ListView x:Name="lvPoint" ItemsSource="{Binding}">
  <ListView.ItemTemplate>
    <DataTemplate>
      <StackPanel>
        <TextBlock Text="{Binding color, Mode=TwoWay}" />
            <ListBox ItemsSource="{Binding SOMETHING, Mode=TwoWay}">
              <ListBox.ItemTemplate>
                <DataTemplate>
                  <StackPanel>
                    <TextBlock Text="{Binding weight, Mode=OneWay}" />                                                
                  </StackPanel>
                </DataTemplate>
              </ListBox.ItemTemplate>
           </ListBox>
       </StackPanel>
     </DataTemplate>
   </ListView.ItemTemplate>
 </ListView>

我在代码中为外部ListBox设置了DataContext:

lvPoint.DataContext = lines;

如何设置内部 ListBox 的 DataContext 以显示每行的点?

【问题讨论】:

    标签: wpf xaml data-binding windows-8.1


    【解决方案1】:

    您的Line 模型不适合这种情况。它应该有一个名为Points 的属性,其中包含属于该线的感兴趣的点。那么 Binding 就很简单了:

    class Line {
      public string line_id  { get; set; }
      public string color { get; set; }
      ObservableCollection<Point> _points;
      public ObservableCollection<Point> Points {
        get {
            if (_points == null) _points = new ObservableCollection<Point>();
            return _points;
        }
      }
    }
    

    然后在 XAML 代码中,您可以像这样将 Path 设置为 Points

    <ListBox ItemsSource="{Binding Points, Mode=TwoWay}">
        <ListBox.ItemTemplate>
           <DataTemplate>
              <StackPanel>
                <TextBlock Text="{Binding weight, Mode=OneWay}" />                  
              </StackPanel>
           </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    

    上面的模型只是一个展示主要思想的例子。完整的实现当然应该根据当前的项目而有所不同和更先进。

    更新:在不使用上述模型的情况下,您可以尝试使用Converter 作为BindingBinding 直接设置为当前项目(行)。 Converter 会将Line 转换为points(可能基于line_id 和您的查询方法):

    public class LineToPointsConverter : IValueConverter {
       public object Convert(object value, Type targetType, object parameter,
                             System.Globalization.CultureInfo culture){
          var line = value as Line;
          //convert to points by querying the points based on line.line_id here
          return ...
       }
       public object ConvertBack(object value, Type targetType, 
                                 object parameter, 
                                 System.Globalization.CultureInfo culture){
          return Binding.DoNothing;
       }                             
    }
    

    定义LineToPointsConverter 的静态属性或在Resources 中创建该转换器的实例:

    <Window.Resources>
       <local:LineToPointsConverter x:Key="lineToPointsConverter"/>  
    </Window.Resources>
    

    然后在 XAML 代码中设置转换器:

    <ListBox ItemsSource="{Binding Mode=TwoWay, Path=.,
                                 Converter={StaticResource lineToPointsConverter}}">
        <ListBox.ItemTemplate>
           <DataTemplate>
              <StackPanel>
                <TextBlock Text="{Binding weight, Mode=OneWay}" />                  
              </StackPanel>
           </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>  
    

    【讨论】:

    • 我使用的 ORM 不能序列化这样的集合属性,但还是谢谢。
    • @demas 恐怕这是唯一的方法,最直观且符合 XAML 的模型。无论如何,内部 ListBox 内的Binding 具有当前项(行)的上下文。更改上下文也应该更改绑定点集合。您的代码中的points 集合在这里不清楚(它位于哪里?)或者它是DataContext 的成员?如果是这样,它是所有线条的混合点?
    • 是一个单独的集合(每个集合对应DB中的一个表)。我在 Line 和 Point 中使用 line_id 属性将点链接到 Line。
    • @demas 我不熟悉 ORM。看起来您可以使用 Binding Converter 或自定义 MarkupExtension 从线中获取点。请参阅我的更新以了解其中一种方法(使用 Converter)。我不确定这是否有效,但值得一试。
    猜你喜欢
    • 2011-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-22
    相关资源
    最近更新 更多