Search code examples
wpfmvvmtabcontroltabitem

How to add a Rich Text Box to a Tab item so that can be added to a Tab Control in MVVM?


How to add a RichTextBox to a Tab item so that can be added to a Tab Control and display corresponding content in the RichTextBox dynamically in MVVM format.

ViewModel

private ObservableCollection<TabItem> TabControl()
        {
            ObservableCollection<TabItem> Tabs= new ObservableCollection<TabItem>();

            return Tabs;
        }

Controller

  private void AddNewTabItem(string selectedItem)
    {
    try
        {

            System.Windows.Controls.RichTextBox richtextbox = new System.Windows.Controls.RichTextBox();
            richtextbox.Name = "richtextbox" + selectedItem;
            BrushConverter BC = new BrushConverter();
            richtextbox.Background = (SolidColorBrush)(BC.ConvertFrom("#FF098BBB"));
            richtextbox.Foreground = System.Windows.Media.Brushes.WhiteSmoke;
            richtextbox.IsReadOnly = true;

            TabItem m_tabItem = new TabItem();

            m_tabItem.Header = selectedItem;
            m_tabItem.Name = "tab" + selectedItem; 


            if (TabControl.Items.Count == 0)
            {
                TabControl.Items.Insert(0, m_tabItem);
                TabControl.SelectedIndex = msgTracerTabControl.Items.Count - 1;
            }
            else
            {
                TabControl.Items.Insert(msgTracerTabControl.Items.Count - 1, m_tabItem);
                TabControl.SelectedIndex = msgTracerTabControl.Items.Count - 2;
            }




            m_tabItem.Content = new System.Windows.Controls.RichTextBox();
            m_tabItem.Content = richtextbox;
            Tabs.add(m_tabItem);
        }
        catch (Exception EX)
        {

        }

    }

View

<TabControl  Grid.Column="1" Grid.Row="1" ItemsSource="{Binding TabControl}"  }"/>

I have used this code and working fine and this is not in MVVM this is WAF Architecture in that i'm using MVVM concept.


Solution

  • You're not thinking MVVM. In a ViewModel you would not directly access UI elements but would rather set up bindings and data templates which would render your Viewmodels correctly. The correct approach is to have 2 viewmodels, 1 to act as a master and the second to act as the underlying DataContext for each tab.

    A simple example would be something like this:

    MainViewModel

        public class MainViewModel : BindableBase
        {
            private int _tabSuffix;
            public ObservableCollection<TextViewModel> TextTabs { get; set; } = new ObservableCollection<TextViewModel>();
    
        public DelegateCommand AddNewTabCommand { get; set; }
    
        public MainViewModel()
        {
            AddNewTabCommand = new DelegateCommand(OnAddNewTabCommand);
        }
    
        private void OnAddNewTabCommand()
        {
            TextTabs.Add(new TextViewModel()
            {
                Header = $"Tab #{_tabSuffix++}"
            });
        }
    }
    

    MainView

    <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition />
            </Grid.RowDefinitions>
            <Button Grid.Row="0" Content="Add new tab item" Command="{Binding AddNewTabCommand}"></Button>
            <TabControl Grid.Row="1"
                        ItemsSource="{Binding TextTabs}"
                        IsSynchronizedWithCurrentItem="True">
                <!-- Defines the header -->
                <TabControl.ItemTemplate>
                    <DataTemplate DataType="{x:Type so44497239:TextViewModel}">
                        <TextBlock Text="{Binding Header}" />
                    </DataTemplate>
                </TabControl.ItemTemplate>
    
                <!-- defines the context of each tab -->
                <TabControl.ContentTemplate>
                    <DataTemplate DataType="{x:Type so44497239:TextViewModel}">
                        <RichTextBox Background="#FF098BBB" Foreground="WhiteSmoke" IsReadOnly="False" />
                    </DataTemplate>
                </TabControl.ContentTemplate>
            </TabControl>
        </Grid>
    

    TextViewModel

    public class TextViewModel : BindableBase
        {
            public string Header { get; set; }
            public Brush BackgroundBrush { get; set; }
            public Brush ForegroundBrush { get; set; }
    
            public string Document { get; set; }
        }
    

    In this example, the main viewmodel has no knowledge of the View but merely adds items to it's own ObservableCollection. The TabControl itself, through the binding to TextTabs, adds it's own tab items and renders them using the ItemTemplate and ContentTemplate properties.

    Download code here