Dynamically updating TabControl content at run time

So here is the problem. I have a window divided into three panels. The middle contains the drawing surface, and on the left is the tab control. Each tab control tab consists of a list of buttons that should open a new menu in the right panel. I can't figure out how to do this in code, so I resorted to individually creating each button at runtime in C #. There seems to be a better way for this. I am currently calling the function below for button press events to draw another menu in the TabControl dashboard called "tabctrl" at runtime. It takes a string argument to indicate which set of menus to draw, although at the moment I just wrote the code for one of the menus. Below is the code for the function and xml. Is there a better way to do this?

XML:

<TabControl DockPanel.Dock="Right" Background="White" x:Name="tabctrl"> <TabItem Height ="38" Name="Tab1" Header="tab3"/> </TabControl> 

FROM#:

 private void menuOpen(string menuSelected) { //Logic statement for what menu is being opened switch (menuSelected) { case "BackGround": { //Remove Current Tabs //Initialize Tab Item, set title, and add tab item to tab control TabItem BackGround = new TabItem(); BackGround.Header = "BackGround"; tabctrl.Items.Insert(1, BackGround); BackGround.Height = 38; //Initialize Stack Panel, set orientation, and add to tab control StackPanel panel = new StackPanel(); panel.Orientation = Orientation.Vertical; BackGround.Content = panel; //Initialize Menu Items Button AddMap = new Button(); Button AddDemoMap = new Button(); Button RemoveMap = new Button(); Button MoveSelected = new Button(); Button Properties = new Button(); Button ScaleBackground = new Button(); //Define Button Text AddMap.Content = "Add Map"; AddDemoMap.Content = "Add Demo Map"; RemoveMap.Content = "Remove Map"; MoveSelected.Content = "Move Selected Map to Top of List"; Properties.Content = "Properties"; ScaleBackground.Content = "Scale Background to Pipes"; AddMap.Height = 50; AddDemoMap.Height = 50; RemoveMap.Height = 50; MoveSelected.Height = 50; Properties.Height = 50; ScaleBackground.Height = 50; //Add Buttons to StackPanel panel.Children.Add(AddMap); panel.Children.Add(AddDemoMap); panel.Children.Add(RemoveMap); panel.Children.Add(MoveSelected); panel.Children.Add(Properties); panel.Children.Add(ScaleBackground); } break; 
+3
source share
1 answer

Good ... allows you to:

First of all, you must learn to think about your interface in an abstract way:

What is TabControl?

This is a graphical representation of the widget list in which the user can have 1 active widget at a time. These widgets have a title (tab element text), a visibility state, and an On / Off state.

What is a bunch of folded buttons? (toolbar if you want to call it)

This is a graphical representation of a list of actions that a user can perform at any given time. These actions have a description (the contents of the button), possibly an associated icon or graphic image, as well as the On / Off status.

What is ContextMenu or menu?

The same as above is a graphical representation of the list of actions that the user can perform.

How can I create a dynamic TabControl in WPF?

This is XAML for the WPC TabControl, which 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); } } } 

In this example, each element (TabItem) in the TabControl will be bound to one of the ViewModels, then it is just a matter of inheriting the base TabViewModel for each of your tabs and creating the correct DataTemplate for each.

As you can see in this example, I in no way create or manipulate any user interface elements in the code. This simplifies all A LOT code and helps maintain a clear separation between logic and user interface. You can apply the same concept to everything in WPF.

+6
source