0

新手WPF我正在努力理解如何基于TreeView控件提供单个数据输入表单的概念。

简单来说,我有一个分成两列的窗口,在左边我有一个TreeView静态数据,如下所示

        <TreeView Name="treeView1" VerticalAlignment="Top"    SelectedItemChanged="TreeViewItem_Selected" >
        <TreeViewItem Header="Settings"  IsExpanded="True" IsSelected="True">
            <TreeViewItem Header="Status" IsExpanded="True" >
                    <TreeViewItem Header="Info"/>
                    <TreeViewItem Header="Connection"/>
                </TreeViewItem>
            <TreeViewItem Header="Settings" IsExpanded="True">
                    <TreeViewItem Header="Options"/>
                    <TreeViewItem Header="IP"/>
                </TreeViewItem>
             </TreeViewItem>
        </TreeViewItem>
    </TreeView>

我在后面的代码中提供了选定的节点信息。

我需要在右侧列中有一个表格,该表格可能包含许多不同的控件,每个视图都是单独的,并根据从TreeView SelectedItemChanged

我认为我在理解模板等的上下文时遇到了问题,所以我只是不知道如何让它工作。我原以为这是一个主流模型,它应该很简单,但开始认为情况可能并非如此,应该使用 C++。

任何指针和/或示例代码都会有很大帮助。

非常感谢您的时间。

4

1 回答 1

0

但开始认为情况可能并非如此,应该使用 C++。

不,不是真的,问题在于 WPF 需要与大多数 UI 框架完全不同的范式和“思维方式”。

这就是所谓的MVVM

以下是我对您所描述的内容的看法:

<Window x:Class="MiscSamples.TreeUI"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MiscSamples"
        Title="TreeUI" Height="300" Width="300">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <TreeView ItemsSource="{Binding}" MinWidth="200" x:Name="TreeView">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                    <TextBlock Text="{Binding DisplayName}"/>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>

        <ContentPresenter Grid.Column="1" Content="{Binding SelectedItem, ElementName=TreeView}">
            <ContentPresenter.Resources>
                <DataTemplate DataType="{x:Type local:TreeViewModelBase}">
                    <!-- Empty -->
                </DataTemplate>

                <DataTemplate DataType="{x:Type local:SettingsViewModel}">
                    <TextBlock Text="{Binding SomeSetting}"/>
                </DataTemplate>

                <DataTemplate DataType="{x:Type local:InfoViewModel}">
                    <StackPanel>
                        <TextBox Text="{Binding SomeInfoText}"/>
                        <ListBox ItemsSource="{Binding Infos}"/>
                    </StackPanel>
                </DataTemplate>
            </ContentPresenter.Resources>
        </ContentPresenter>
    </Grid>
</Window>

后面的代码(样板,只是实例化层次结构以支持示例):

 public partial class TreeUI : Window
    {
        public TreeUI()
        {
            InitializeComponent();

            DataContext = new List<TreeViewModelBase>
                              {
                                  new SettingsViewModel()
                                      {
                                          Children =
                                              {
                                                  new TreeViewModelBase()
                                                      {
                                                          DisplayName = "Status",
                                                          Children =
                                                              {
                                                                  new InfoViewModel(),
                                                                  new TreeViewModelBase() {DisplayName = "Connection"}
                                                              }
                                                      }
                                              }
                                      }
                              };
        }
    }

视图模型:

public class TreeViewModelBase: PropertyChangedBase
    {
        public string DisplayName { get; set; }

        private List<TreeViewModelBase> _children;
        public List<TreeViewModelBase> Children
        {
            get { return _children ?? (_children = new List<TreeViewModelBase>()); }
        }
    }

    public class SettingsViewModel: TreeViewModelBase
    {
        public string SomeSetting { get; set; }

        public SettingsViewModel()
        {
            DisplayName = "Settings";
            SomeSetting = "This is Some Setting in the Settings section";
        }
    }

    public class InfoViewModel: TreeViewModelBase
    {
        public string SomeInfoText { get; set; }

        public List<string> Infos { get; set; } 

        public InfoViewModel()
        {
            DisplayName = "Info";
            SomeInfoText = "Welcome to the Info section!";
            Infos = Enumerable.Range(1, 100).Select(x => "Info Text " + x.ToString()).ToList();
        }
    }

支持类 (PropertyChangedBase)

public class PropertyChangedBase:INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            Application.Current.Dispatcher.BeginInvoke((Action) (() =>
                {
                    PropertyChangedEventHandler handler = PropertyChanged;
                    if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
                }));
        }
    }

结果:

在此处输入图像描述

有几点需要注意:

  • 这些TreeViewModelBase派生类中的每一个都代表一个“小部件”。然后,您可以添加相关属性以在每个属性上存储实际的设置值。
  • DataTemplates这些使用XAML 中所示的正确方法呈现到屏幕的右侧部分。您还可以将每个“小部件视图”单独UserControl放置,以保持 MainWindow.XAML 干净。
  • 在我的示例中,没有一个事件或一行代码可以操作 UI 元素。它只是简单、简单的属性和INotifyPropertyChanged. 这就是您在 WPF 中编程的方式。不需要SelectedIndexChanged或类似的东西。
  • 为了支持双向绑定,您的属性必须OnPropertyChanged("PropertyName");.
  • 如果您需要进一步的帮助,请告诉我。
于 2013-04-18T18:31:33.373 回答