WPF treeview提供自定义数据输入视图

时间:2013-04-18 12:08:18

标签: wpf view treeview

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 ++。

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

非常感谢你的时间。

1 个答案:

答案 0 :(得分: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>

Code Behind(Boilerplate,只是实例化层次结构以支持该示例):

 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"}
                                                              }
                                                      }
                                              }
                                      }
                              };
        }
    }

的ViewModels:

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));
                }));
        }
    }

结果:

enter image description here

有几点需要注意:

  • 这些TreeViewModelBase派生类中的每一个都代表一个“小部件”。然后,您可以添加相关属性以存储每个属性的实际设置值。
  • 使用正确的DataTemplates将它们渲染到屏幕的右侧部分,如XAML中所示。您还可以将每个“窗口小部件视图”放在单独的UserControl中,以保持MainWindow.XAML的清洁。
  • 在我的示例中没有单个事件或单行代码来操纵UI元素。它只是简单,简单的属性和INotifyPropertyChanged 。这就是你在WPF中编程的方式。不需要SelectedIndexChanged或类似的东西。
  • 为了支持双向绑定,您的媒体资源必须为OnPropertyChanged("PropertyName");
  • 如果您需要进一步的帮助,请告诉我。