但开始认为情况可能并非如此,应该使用 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");
.
- 如果您需要进一步的帮助,请告诉我。