Problem with TabControl Template and Binding in WPF.

Sherry Shi 41 Reputation points
2022-03-07T06:43:45.72+00:00

I would like to put image in TabControl header using binding, but below code doesn't work. I would like to know why, and how to do it? Thanks in advance :)

1、MainWindow.xaml

<Window x:Class="WpfApp3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <TabControl Height="300" ItemsSource="{Binding TabCollection}">
            <!-- this is the header template-->
            <TabControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <Label Content="{Binding Path=DisplayIndex}" />
                        <Image Source="{Binding Path=ContentObject.BackgroundImageSource}" Width="50"></Image>
                    </StackPanel>
                </DataTemplate>
            </TabControl.ItemTemplate>
            <!-- this is the body of the TabItem template-->
            <TabControl.ContentTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Path=ContentObject.ShowContent}" />
                </DataTemplate>
            </TabControl.ContentTemplate>
        </TabControl>
        <Button Content="Button" HorizontalAlignment="Left" Margin="273,391,0,0" VerticalAlignment="Top" Click="Button_Click"/>
    </Grid>
</Window>

2、MainWindow.xaml.cs

 public partial class MainWindow : Window
    {
        public MainWindow()
        {
            vm = new WindowVM();
            this.DataContext = vm;
            InitializeComponent();
        }

        private WindowVM vm;

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            vm.Init();
        }
    }

3、WindowVM

 public class WindowVM : INotifyPropertyChanged
    {
        #region Fields & Properties

        public event PropertyChangedEventHandler PropertyChanged;

        public ObservableCollection<ITestView> TabCollection { get; } = new ObservableCollection<ITestView>();

        #endregion

        public void Init()
        {
            List<ITestView> list = new List<ITestView>()
            {
                new Test1View(),
                // new Test2View()...
            };

            foreach (ITestView test in list)
            {
                TabCollection.Add(test);
            }
        }
    }

4、Interface

 public interface ITestView
    {
        IContentTest ContentObject { get; set; }
        int DisplayIndex { get; set; }
    }

    public interface IContentTest
    {
        string ShowContent { get; set; }
        ImageSource BackgroundImageSource { get; set; }
    }

5、Test1View.xaml & Test1View.xaml.cs & ContentTest1

<UserControl x:Class="WpfApp3.Test1View"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WpfApp3"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>

    </Grid>
</UserControl>


public partial class Test1View : UserControl,ITestView
    {
        public Test1View()
        {
            InitializeComponent();
        }

        #region ITestView Members

        public IContentTest ContentObject { get; set; } = new ContentTest1();

        public int DisplayIndex { get; set; } = 1;

        #endregion

    }


 public class ContentTest1 : IContentTest, INotifyPropertyChanged
    {
        public ContentTest1()
        {
            ShowContent = "TestAAA";

            // in ResourceDictionary: <ImageSource x:Key="Image111">aaa.png</ImageSource>
            BackgroundImageSource = Application.Current.TryFindResource("Image111") as ImageSource;
        }

        #region IContentTest Members

        private string _showContent;
        public string ShowContent
        {
            get => _showContent;
            set
            {
                _showContent = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ShowContent)));
            }
        }

        private ImageSource _backgroundImageSource;
        public ImageSource BackgroundImageSource
        {
            get => _backgroundImageSource;
            set
            {
                _backgroundImageSource = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(BackgroundImageSource)));
            }
        }

        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

    }
Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,674 questions
XAML
XAML
A language based on Extensible Markup Language (XML) that enables developers to specify a hierarchy of objects with a set of properties and logic.
765 questions
0 comments No comments
{count} votes

Accepted answer
  1. Hui Liu-MSFT 38,256 Reputation points Microsoft Vendor
    2022-03-07T07:59:05.783+00:00

    Hi,@Sherry Shi. Welcome to Microsoft Q&A. Based on the problem description that you want to use binding to put an image into the TabControl header, I completed the example below. If you want to achieve the following effect, you could refer to its code. If I misunderstood, please let me know.
    MainWinow.xaml:

     <Grid>  
            <TabControl Height="300" ItemsSource="{Binding TabCollection}">  
                <TabControl.ItemTemplate>  
                    <DataTemplate>  
                        <StackPanel>  
                            <Label Content="{Binding MyHeader}" />  
                            <Image Source="{Binding ImageHeader}" Width="50"></Image>  
                        </StackPanel>  
                    </DataTemplate>  
                </TabControl.ItemTemplate>  
                <TabControl.ContentTemplate>  
                    <DataTemplate>  
                        <TextBlock Text="{Binding MyContents}" />  
                    </DataTemplate>  
                </TabControl.ContentTemplate>  
            </TabControl>  
            <Button Content="Button" HorizontalAlignment="Left" Margin="273,391,0,0" VerticalAlignment="Top" Click="Button_Click"/>  
        </Grid>  
    

    MainWindow.xaml.cs:

    using System;  
    using System.Collections.Generic;  
    using System.Collections.ObjectModel;  
    using System.ComponentModel;  
    using System.Runtime.CompilerServices;  
    using System.Windows;  
    using System.Windows.Media.Imaging;  
    
      
    namespace TabControlDemo  
    {  
      public partial class MainWindow : Window  
      {  
        public MainWindow()  
        {  
          vm = new WindowVM();  
          this.DataContext = vm;  
          InitializeComponent();  
        }  
        private WindowVM vm;  
    
      
        private void Button_Click(object sender, RoutedEventArgs e)  
        {  
          vm.Init();  
        }  
      }  
      public class WindowVM : INotifyPropertyChanged  
      {  
    
          
        public ObservableCollection<MyContent> TabCollection { get; } = new ObservableCollection<MyContent>();  
    
      
        public void Init()  
        {  
          List<MyContent> list = new List<MyContent>();  
          list.Add(new MyContent(){ MyHeader="Tab 1" , ImageHeader= new BitmapImage(new Uri("spring.jpg", UriKind.Relative)), MyContents="Content 1" });  
          list.Add(new MyContent(){ MyHeader="Tab 2" , ImageHeader= new BitmapImage(new Uri("images.jpg", UriKind.Relative)), MyContents="Content 2" });  
          list.Add(new MyContent(){ MyHeader="Tab 3" , ImageHeader= new BitmapImage(new Uri("spring1.jpg", UriKind.Relative)), MyContents="Content 3" });  
    
      
          foreach (MyContent test in list)  
          {  
            TabCollection.Add(test);  
          }  
        }  
        public event PropertyChangedEventHandler PropertyChanged;  
      }  
      public class MyContent : INotifyPropertyChanged  
    
        
      {  
        public string myHeader;  
        public string MyHeader  
        {  
          get { return myHeader; }  
          set  
          {  
            myHeader = value;  
            OnPropertyChanged();  
          }  
        }  
        public BitmapImage imageHeader;  
        public BitmapImage ImageHeader  
        {  
          get { return imageHeader; }  
          set  
          {  
            imageHeader = value;  
            OnPropertyChanged();  
          }  
        }  
        public string myContents ;  
        public string MyContents  
        {  
          get { return myContents; }  
          set  
          {  
            myContents = value;  
            OnPropertyChanged();  
          }  
        }  
        protected void OnPropertyChanged([CallerMemberName] string name = null)  
        {  
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));  
        }  
        public event PropertyChangedEventHandler PropertyChanged;  
      }  
    }  
    

    The result:
    180540-8.gif

    Update:

    I defined two interfaces: ITestView and IContentTest, as well as concrete classes that implement these interfaces. These classes define the content and properties of the tabs in the TabControl.

    MainWindow.xaml:

    <Grid>  
            <TabControl Height="300" ItemsSource="{Binding TabCollection}">  
                <TabControl.ItemTemplate>  
                    <DataTemplate>  
                        <StackPanel>  
                            <Label Content="{Binding DisplayIndex}" />  
                            <Image Source="{Binding ContentObject.BackgroundImageSource}" Width="50"></Image>  
                        </StackPanel>  
                    </DataTemplate>  
                </TabControl.ItemTemplate>  
                <TabControl.ContentTemplate>  
                    <DataTemplate>  
                        <TextBlock Text="{Binding ContentObject.ShowContent}" />  
                    </DataTemplate>  
                </TabControl.ContentTemplate>  
            </TabControl>  
            <Button Content="Button" HorizontalAlignment="Left" Margin="273,391,0,0" VerticalAlignment="Top" Click="Button_Click"/>  
        </Grid>  
    

    MainWindow.xaml.cs:

    using System;  
    using System.Collections.Generic;  
    using System.Collections.ObjectModel;  
    using System.Windows;  
    using System.Windows.Media.Imaging;  
    
      
    namespace TabControlInerface  
    {  
        public partial class MainWindow : Window  
        {  
            public MainWindow()  
            {  
                vm = new WindowVM();  
                this.DataContext = vm;  
                InitializeComponent();  
            }  
            private WindowVM vm;  
            private void Button_Click(object sender, RoutedEventArgs e)  
            {  
                vm.Init();  
            }  
        }  
        public class WindowVM   
        {  
            public ObservableCollection<Con> TabCollection { get; } = new ObservableCollection<Con>();  
    
      
            public void Init()  
            {  
                List<Con> list = new List<Con>() { new Con()  };  
                foreach (Con test in list)  
                {  
                    TabCollection.Add(test);  
                }  
            }  
        }  
        public interface ITestView  
        {  
            IContentTest ContentObject { get; set; }  
            int DisplayIndex { get; set; }  
        }  
        public interface IContentTest  
        {  
            string ShowContent { get; set; }  
            BitmapImage BackgroundImageSource { get; set; }  
        }  
        public class MyContent :IContentTest  
        {  
            public string ShowContent { get; set; }  
            public BitmapImage BackgroundImageSource { get; set; }  
            public MyContent()  
            {  
                ShowContent = "header1";  
                BackgroundImageSource = new BitmapImage(new Uri("spring.jpg", UriKind.Relative));  
            }  
        }  
        public class Con : ITestView  
        {  
            public IContentTest ContentObject { get; set; } = new MyContent();  
            public int DisplayIndex { get; set; } = 1;  
        }  
    }  
    

    The result:
    180993-image.png


    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


0 additional answers

Sort by: Most helpful