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 ++。
任何指针和/或示例代码都会有很大的帮助。
非常感谢你的时间。
答案 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));
}));
}
}
结果:
有几点需要注意:
TreeViewModelBase
派生类中的每一个都代表一个“小部件”。然后,您可以添加相关属性以存储每个属性的实际设置值。DataTemplates
将它们渲染到屏幕的右侧部分,如XAML中所示。您还可以将每个“窗口小部件视图”放在单独的UserControl
中,以保持MainWindow.XAML的清洁。INotifyPropertyChanged
。这就是你在WPF中编程的方式。不需要SelectedIndexChanged
或类似的东西。OnPropertyChanged("PropertyName");
。