【问题标题】:DataGrid in a TreeView in WPFWPF 中 TreeView 中的 DataGrid
【发布时间】:2017-07-20 19:15:33
【问题描述】:

我正在尝试绑定到下面DataGrid 中的StringValue 对象集合。但是每个项目都显示在单独的行中。

我希望它具有柱状显示。例如,值 565477 和 65656 应显示在一行中。

XAML:

<TreeView>
    <TreeViewItem Header="Warnings">
        <TreeView ItemsSource="{Binding WarningCategories}">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Path=Warnings}">
                    <TextBlock Text="{Binding Path=Category}" />
                    <HierarchicalDataTemplate.ItemTemplate>
                        <DataTemplate>
                            <DataGrid ItemsSource="{Binding Fields}" AutoGenerateColumns="True" HeadersVisibility="None">
                            </DataGrid>                                
                        </DataTemplate>
                    </HierarchicalDataTemplate.ItemTemplate>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </TreeViewItem>
</TreeView>

代码隐藏:

   public class ViewModel : INotifyPropertyChanged
   {
      public event PropertyChangedEventHandler PropertyChanged;

      public ObservableCollection<WarningCategory> WarningCategories { get; set; }


      public ViewModel()
      {
         WarningCategories = new ObservableCollection<WarningCategory>();

         ObservableCollection<Warning> warnings = new ObservableCollection<Warning>
         {
            new Warning( new StringValue("565477"), new StringValue("65656")),
            new Warning( new StringValue("767455"), new StringValue("75642")),
         };


         WarningCategories.Add(new WarningCategory("Warning One", warnings));



         warnings = new ObservableCollection<Warning>
         {
            new Warning( new StringValue("565477"), new StringValue("65656")),
            new Warning( new StringValue("767455"), new StringValue("75642")),
         };



         WarningCategories.Add(new WarningCategory("Warning Two", warnings));
      }



      [NotifyPropertyChangedInvocator]
      protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
      {
         var handler = PropertyChanged;
         if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
      }
   }

   public class WarningCategory
   {
      public string Category { get; set; }

      private ObservableCollection<Warning> m_warnings;

      public ObservableCollection<Warning> Warnings

      {
         get
         {
            return m_warnings ?? (m_warnings = new ObservableCollection<Warning>());
         }
      }


      public WarningCategory(string category, ObservableCollection<Warning> animals)

      {
         Category = category;

         m_warnings = animals;
      }
   }

   public class Warning

   {
      public ObservableCollection<StringValue> Fields { get; set; }

      public Warning(params StringValue[] fields)

      {
         Fields = new ObservableCollection<StringValue>(fields);
      }
   }

   public class StringValue
   {
      public StringValue(string s)
      {
         Value = s;
      }
      public string Value { get; set; }
   }

我希望最终结果是这样的:

到目前为止我的解决方法,但不幸的是它不支持多选!

<ItemsControl ItemsSource="{Binding Fields}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Value}" Width="150"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

【问题讨论】:

  • 您真的想在数据网格中拥有多行吗?为什么要使用数据网格?
  • @DanField 实际上没有。但我希望能够选择整行。我在 DataGrid 中发现了这种功能-
  • 您能否在帖子中添加一些内容,显示您期望的最终输出结果?
  • @DanField 我添加了。
  • 我不是 100% 清楚您现在想要多选的内容 - 单个值?行?两者都有?

标签: c# wpf xaml datagrid treeview


【解决方案1】:

我建议不要使用DataGrid,我还会重新设计您的模板当前的工作方式。我认为这样的东西非常接近你想要的:

<TreeView>
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type local:WarningCategory}" ItemsSource="{Binding Warnings}">
            <TextBlock Text="{Binding Path=Category}" />
            <HierarchicalDataTemplate.ItemTemplate>
                <DataTemplate>
                    <ListBox ItemsSource="{Binding}" SelectionMode="Extended">
                        <TextBlock Text="{Binding FieldsPivoted}" />
                    </ListBox>
                </DataTemplate>
            </HierarchicalDataTemplate.ItemTemplate>
        </HierarchicalDataTemplate>
        <!--<DataTemplate DataType="{x:Type local:Warning}">
            <TextBlock Text="{Binding FieldsPivoted}"    />
        </DataTemplate>-->
    </TreeView.Resources>

    <TreeViewItem Header="Warnings" ItemsSource="{Binding WarningCategories}" />
</TreeView>

将此添加到您的 Warning 类中:

public string FieldsPivoted
{
    get
    {
        return string.Join(", ", Fields.Select(x => x.Value));
    }
}

看起来像这样:

使用列表应该允许以您正在寻找的方式进行多项选择。

【讨论】:

  • Dan ,我现在正在使用类似的方法,但不幸的是,这并不能解决我的问题。请看我的编辑:
  • 已编辑 - 它现在有一个列表框,允许选择多行。
  • 谢谢丹,能否请您上传图片。我错过了一些东西。我现在只能选择一行。
  • 太棒了!但我觉得有些不对劲。当您单击它时,它只是选择。不持有作为列表框默认行为的控件-
【解决方案2】:

使用带有水平 StackPanel 的 ListBox 代替 DataGrid(可以旋转,但有问题)用于 ItemsPanel

<DataTemplate>
    <ListBox ItemsSource="{Binding Fields}">
     <ListBox.ItemsPanel>
      <ItemsPanelTemplate>
        <StackPanel Orientation="Horizontal"/>
      </ItemsPanelTemplate>
     </ListBox.ItemsPanel>

     <ListBox.ItemTemplate>
      <DataTemplate>
        <TextBlock Text="{Binding Path=Value}"/>
      </DataTemplate>
     </ListBox.ItemTemplate>
    </ListBox>     

    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="IsSelected" 
                    Value="{Binding Path=IsSelected, RelativeSource={RelativeSource AncestorType=TreeViewItem}}"/>
        </Style>
    </ListBox.ItemContainerStyle>
</DataTemplate>

为了启用全行选择,我创建了 ListBoxItem.IsSelected 到 TreeViewItem.IsSelected 的绑定

【讨论】:

  • 谢谢 Ash,我希望能够选择整行。
  • 谢谢。它有效,但只有当我单击一个单元格时才会选择整行。悬停时只选择一个单元格。
  • @Vahid,您需要选择单个值吗?还是总是整排?如果总是整行,则将 ListBox 替换为 ItemsControl(并删除 ItemContainerStyle)。 ItemsControl 不支持选择项目
  • 我希望能够多选行。
【解决方案3】:

创建一个用于数据绑定的新类。

Public class MainClass
{
    public void MainClass(string row,string rowValue)
    {
        Row = row;
        RowValue= rowValue;
    }
  public string Row
  {
    get;
    set;
  }
  public string RowValue
  {
    get;
    set;
  }
}

视图模型

        private ObservableCollection<MainClass> _mainClassList = new ObservableCollection<MainClass>();
        public ObservableCollection<MainClass> MainClassList
        {
            get { return _mainClassList; }
            set
            {
                _mainClassList= value;
                NotifyPropertyChanged(m => m.MainClassList);
            }
        }
        public void AddItems()
        {
         _mainClassList.Add(new MainClass("row1","row1Value"))
         _mainClassList.Add(new MainClass("row2","row2Value"))
         MainClassList = _mainClassList;
        }

XAML

 <DataGrid CanUserAddRows="True" RowHeight="23" AutoGenerateColumns="False" ItemsSource="{Binding MainClassList}">
                <DataGrid.Columns>
                    <DataGridTextColumn Width="70*" Header="Column1" Binding="{Binding Row,Mode=OneWay}"></DataGridTextColumn>
                    <DataGridTextColumn Width="70*" Header="Column2" Binding="{Binding RowValue,Mode=OneWay}"></DataGridTextColumn>
                </DataGrid.Columns>
 </DataGrid>

【讨论】:

  • 什么是 Column1Value?
  • @Vahid 它可以正常工作并且完全符合您的要求,为什么要投反对票?
猜你喜欢
  • 2012-08-09
  • 2011-07-27
  • 1970-01-01
  • 2016-10-11
  • 2014-12-02
  • 2011-07-12
  • 2017-02-27
  • 2011-04-01
  • 1970-01-01
相关资源
最近更新 更多