Ok... lets see:
First of all, you must learn to think your UI in an abstract way:
What is a TabControl?
It's a graphical representation of a List of widgets, where the user can have 1 active widget at a time. These widgets have a Title (the tab item text), a Visibility state, and an Enabled/Disabled state.
What is a bunch of stacked buttons? (toolbar, if you want to call it that)
It's a graphical representation of a List of actions that the user can perform at any given time. These actions have a Description (the button's content), possibly an associated icon or graphical image, and an Enabled / Disabled State.
What is a ContextMenu, or a Menu?
The same as above, it's a graphical representation of a list of Actions that the user can perform.
How would I go about creating a dynamic TabControl in WPF?
This is the XAML for a WPF TabControl that supports dynamic Children:
<Window x:Class="WpfApplication4.Window12"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window12" Height="300" Width="300">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
</Window.Resources>
<TabControl ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="IsEnabled" Value="{Binding IsEnabled}"/>
<Setter Property="Visibility" Value="{Binding IsVisible, Converter={StaticResource BoolToVisibilityConverter}}"/>
<Setter Property="Header" Value="{Binding Title}"/>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
</Window>
ViewModel:
public class TabbedViewModel: ViewModelBase
{
private ObservableCollection<TabViewModel> _items;
public ObservableCollection<TabViewModel> Items
{
get { return _items ?? (_items = new ObservableCollection<TabViewModel>()); }
}
private ViewModelBase _selectedItem;
public ViewModelBase SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
NotifyPropertyChange(() => SelectedItem);
}
}
}
public class TabViewModel: ViewModelBase
{
private string _title;
public string Title
{
get { return _title; }
set
{
_title = value;
NotifyPropertyChange(() => Title);
}
}
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
NotifyPropertyChange(() => IsEnabled);
}
}
private bool _isVisible;
public bool IsVisible
{
get { return _isVisible; }
set
{
_isVisible = value;
NotifyPropertyChange(() => IsVisible);
}
}
}
With this example, each item (TabItem) in the TabControl will be bound to one of the ViewModels, then it's just a matter of inheriting the base TabViewModel for each of your tabs and creating a proper DataTemplate
for each.
As you can see in this example, I'm in no way creating or manipulating ANY UI elements in code. This simplifies all code A LOT, and helps maintain a clear separation between logic and UI.
You can apply this same concept to everything in WPF.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…