简体   繁体   English

WPF 树视图和数据网格选择已更改

[英]WPF treeview and datagrid selection changed

I am working on this WPF project with a Treeview and DataGrid .我正在使用TreeviewDataGrid处理这个 WPF 项目。

On the left side is a tree structure with some documents shown on the right side in the data grid.左侧是一个树状结构,其中一些文档显示在数据网格的右侧。 If we change the selected item in the tree view, the datagrid display should change.如果我们更改树视图中的选定项,则数据网格显示应更改。 All Documents should show all and so on. All Documents 应该显示 all 等等。 Can someone point me in the right direction?有人可以指出我正确的方向吗? I have this working in winforms with some view models.我在带有一些视图模型的 winforms 中工作。 Just doing this in WPF seems hard.在 WPF 中这样做似乎很难。 I am just learning WPF.我只是在学习 WPF。 Here is what I have done so far.这是我到目前为止所做的。 Now the part where I bring in the tree is where some help or websites would be good现在我引入树的部分是一些帮助或网站会很好的地方

        <Grid ShowGridLines="False">


            <DataGrid Name="DataGrid1" AutoGenerateColumns="False" AlternatingRowBackground="AliceBlue">
                <DataGrid.Columns>

                    <DataGridTextColumn Header="Document Type Name" Binding="{Binding DocumentType.DocumentTypeName}" IsReadOnly="True"></DataGridTextColumn>
                    <DataGridTextColumn Header="Status" Binding="{Binding Name}" IsReadOnly="True"></DataGridTextColumn>
                    <DataGridTextColumn Header="Description" Binding="{Binding Description}" IsReadOnly="True"></DataGridTextColumn>

                    <DataGridTextColumn Header="Type" Binding="{Binding Type}" IsReadOnly="True"></DataGridTextColumn>

                </DataGrid.Columns>

            </DataGrid>
        </Grid>

    </StackPanel>

在此处输入图片说明

Since the default TreeView does not support a Binding on SelectedItem, you have to perform an ugly Workaround.由于默认的 TreeView 不支持 SelectedItem 上的绑定,因此您必须执行一个丑陋的解决方法。 Subclass the Treeview and make it bindable first:对 Treeview 进行子类化并首先使其可绑定:

 public class TreeViewA : TreeView {

    public new static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(TreeViewA), new FrameworkPropertyMetadata(null, OnSelectedItemChanged));

    public TreeViewA() {
      base.SelectedItemChanged += this.OnTreeViewSelectedItemChanged;
      this.ItemContainerGenerator.StatusChanged += this.ItemContainerGeneratorOnStatusChanged;
    }

    public new object SelectedItem {
      get {
        return this.GetValue(SelectedItemProperty);
      }
      set {
        this.SetValue(SelectedItemProperty, value);
      }
    }

    private void ItemContainerGeneratorOnStatusChanged(object sender, EventArgs eventArgs) {
      if (this.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated)
        return;
      if (this.SelectedItem != null) {
        this.VisualSelectItem();
      }
    }

    private void VisualSelectItem() {
      var xx = (TreeViewItem)this.ItemContainerGenerator.ContainerFromItem(this.SelectedItem);
      if (xx == null)
        return;
      xx.IsSelected = true;
      xx.BringIntoView();
    }

    private void OnTreeViewSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e) {
      this.SelectedItem = e.NewValue;
    }

    private static void OnSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) {
      if (e.NewValue != null) {
        (sender as TreeViewA)?.VisualSelectItem();
      }
    }

  }

Next, the Gui (Example)接下来,Gui(示例)

<Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <local:TreeViewA ItemsSource="{Binding Documents}" SelectedItem="{Binding SelectedDocument, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
            <TreeView.ItemTemplate>
                <DataTemplate>
                    <WrapPanel>
                        <Image Source="whereever" Width="40" Height="40"/>
                        <TextBlock Text="{Binding Name}"/>
                    </WrapPanel>
                </DataTemplate>
            </TreeView.ItemTemplate>
        </local:TreeViewA>

        <DataGrid Grid.Column="1" ItemsSource="{Binding SubDocuments, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" AutoGenerateColumns="False">
            <DataGrid.Columns>

                <DataGridTextColumn Header="Document Type Name" Binding="{Binding DocumentTypeName}" IsReadOnly="True"></DataGridTextColumn>
                <DataGridTextColumn Header="Status" Binding="{Binding Name}" IsReadOnly="True"></DataGridTextColumn>
                <DataGridTextColumn Header="Description" Binding="{Binding Description}" IsReadOnly="True"></DataGridTextColumn>

                <DataGridTextColumn Header="Type" Binding="{Binding Type}" IsReadOnly="True"></DataGridTextColumn>

            </DataGrid.Columns>

        </DataGrid>
    </Grid>

My Example Model for the Documents:我的文档示例模型:

public class Document {

    public string Name {
      get; set;
    }

    public string DocumentTypeName {
      get; set;
    }

    public string Description {
      get; set;
    }

    public string Type {
      get; set;
    }

  }

Code-Behind of my Example-Window:我的示例窗口的代码隐藏:

public partial class Window1 : INotifyPropertyChanged {

    public Window1() {
      InitializeComponent();
      this._docs.Add(new Document { Name = "Doc1", Type = "docx", Description = "Important Doc", DocumentTypeName = "Word-Document" });
      this._docs.Add(new Document { Name = "Doc2", Type = "xlsx", Description = "Important Calculation", DocumentTypeName = "Excel-Document" });
      this._docs.Add(new Document { Name = "Doc3", Type = "pdf", Description = "Important Contract", DocumentTypeName = "Pdf-Document" });
      this.DataContext = this;


    }

    public Document SelectedDocument {
      get {
        return this._selectedDocument;
      }
      set {
        if (Equals(value, this._selectedDocument))
          return;
        this._selectedDocument = value;
        this.SubDocuments.Clear();
        this.SubDocuments.Add(value);
        this.OnPropertyChanged();
      }
    }

    public ObservableCollection<Document> SubDocuments
    {
      get { return this._subDocuments; }
      set
      {
        if (Equals(value, this._subDocuments)) return;
        this._subDocuments = value;
        this.OnPropertyChanged();
      }
    }

    private readonly ObservableCollection<Document> _docs = new ObservableCollection<Document>();
    private Document _selectedDocument;
    private ObservableCollection<Document> _subDocuments = new ObservableCollection<Document>();
    public ObservableCollection<Document> Documents => this._docs;

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
      this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }


  }

Closure关闭

This snippet should provide you an idea, how it can be done.这个片段应该为您提供一个想法,它是如何完成的。 It surely differs from your actual objects and implementations.它肯定与您的实际对象和实现不同。 But since you stated that you only need a push in the right direction, this might give you a Jumpstart.但既然你说你只需要朝着正确的方向推动,这可能会给你一个快速启动。

Note笔记

I've made this with Code-Behind and the Model does not implement INotifyPropertyChanged because it doesnt really matter in this example.我已经用代码隐藏做了这个,模型没有实现INotifyPropertyChanged因为在这个例子中它并不重要。

Hope this helps.希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM