This is a migrated thread and some comments may be shown as answers.

Binding to content control

5 Answers 915 Views
TabControl
This is a migrated thread and some comments may be shown as answers.
Maxim
Top achievements
Rank 1
Maxim asked on 30 May 2011, 04:31 PM
I'm relatively new to WPF and currently evaluating Telerik components. I got stuck when trying to bind RadTabControl items to content control objects. Probably the automatically generated RadTabItem doesn't like to wrap a content control (e.g. HeaderedContentControl) because regular objects work as expected. Am I trying to accomplish something that can't be done? Below you'll find a example that illustrates what I mean. Any help will be appreciated very much.

XAML:
<Window x:Class="RadControlsWpfApp1.MainWindow"
        xmlns:local="clr-namespace:RadControlsWpfApp1"
        xmlns:diagnostics="clr-namespace:System.Diagnostics;assembly=WindowsBase"
        Title="MainWindow" Height="350" Width="525">
      
    <Window.Resources>
        <DataTemplate x:Key="TabItemTemplate">
            <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                <Image Width="18" Height="18" Source="{Binding Icon}" Stretch="Fill" Margin="0,0,3,0" />
                <TextBlock Text="{Binding Header, diagnostics:PresentationTraceSources.TraceLevel=High}"/>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
  
    <Grid>
        <telerik:RadTabControl
            ItemsSource="{Binding Tabs}"
            ItemTemplate="{StaticResource TabItemTemplate}" />
    </Grid>
</Window>

Code behind:
using System.Windows;
  
namespace RadControlsWpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            DataContext = new MainWindowViewModel();
            InitializeComponent();
        }
    }
}

View model:
using System;
using System.Collections.ObjectModel;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Telerik.Windows.Controls.QuickStart;
  
namespace RadControlsWpfApp1
{
    public class MainWindowViewModel
    {
        private BitmapImage Bullet = new BitmapImage(new Uri("/RadControlsWpfApp1;component/bullet_red.png", UriKind.Relative));
  
        public ObservableCollection<IItem> Tabs { get; set; }
  
        public MainWindowViewModel()
        {
            Tabs = new ObservableCollection<IItem>();
            Tabs.Add(new ItemControl { Header = "Item 1", Icon = Bullet });
            Tabs.Add(new Item { Header = "Item 2", Icon = Bullet });
        }
    }
  
    public interface IItem
    {
        object Header { get; set; }
        ImageSource Icon { get; set; }
    }
  
    public class Item : IItem
    {
        public object Header { get; set; }
        public ImageSource Icon { get; set; }
    }
  
    public class ItemControl : HeaderedContentControl, IItem
    {
        public ImageSource Icon { get; set; }
    }
}

5 Answers, 1 is accepted

Sort by
0
Tina Stancheva
Telerik team
answered on 02 Jun 2011, 02:35 PM
Hi Maxim,

You can bind the RadTabControl to a collection of visual elements like a HeaderedContentControl, but you need to keep in mind that the RadTabControl will place the ContentControls in each RadTabItem.Content. Also, when you bind the TabControl to business objects, the control will use its ItemTemplate/ContentTemplate properties to define how to display the business data. In your code sample you only define an ItemTemplate that is used to display the business data (the second item), but since the first item is a ContentControl it is placed as a Content of the RadTabItem and it is displayed as such.

However, I am not sure what you need to implement exactly but it would be best to follow the approach described in the attached sample. The RadTabControl is bound to a business collection that has both business properties and visual controls. The RadTabControl.ItemTemplate uses the business data to define a Header for each RadTabItem, while the ContentTemplate places the custom HeaderedContentControl inside a ContentControl. Here you can find more info about the Template properties of the RadTabControl.

I hope this info will help you, but if I am missing something or you need more info, please let us know.

All the best,
Tina Stancheva
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Maxim
Top achievements
Rank 1
answered on 03 Jun 2011, 09:18 AM
Thanks Tina for your response. I looked at your example and what you did is encapsulate the content control in a regular object of which I know can be bound to without a problem. I'll try to explain the 'real' situation.

In my project I use Prism and MEF to compose a client shell with selectable modules. By using a region I populate a RadOutlookBar with navigation items defined in the extensions. The navigation item is a RadOutlookBarItem (root of the xaml). So far so good. The navigation item's content is made up by a list box that is bound to collection of views of that extension. The views are derived from HeaderedContentControl and the list box item binds correctly to the control's icon and header properties. Selecting an item activates it in the workspace that is a RadTabControl. So the collections of tabs will contain the selected HeaderedContentControls derivatives. The content of the tab is shown correctly but I can't get the tab header content to bind to the icon and header properties. The latter is what I tried to isolate in the sample posted above.
0
Tina Stancheva
Telerik team
answered on 08 Jun 2011, 01:31 PM
Hello Maxim,

Thank you for clarifying your scenario. From your description I take it that you are using the RadTabControl as a region. This is why I believe that the cause for your issue is the fact that the default region adapter that is used to manage the RadTabControl behavior as a region, doesn't set the RadTabItem's DataContext and HeaderTemplate properties and this is why the icon and header properties aren't displayed in the header of the items.

So if you create a custom region adapter for the RadTabControl, you should be able to implement your scenario. You can find a sample RadTabControl region adapter in this forum thread. Let me know if this helps or if you need more info.

All the best,
Tina Stancheva
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Maxim
Top achievements
Rank 1
answered on 08 Jun 2011, 01:36 PM
You might be right that the desired behaviour can be accomplished by using a custom region adpater. But my sample doesn't use Prism...
0
Tina Stancheva
Telerik team
answered on 13 Jun 2011, 01:23 PM
Hi Maxim,

Doesn't your real-life app use the RadTabControl in a PRISM scenario? If it does, it is best to create a region adapter as I previously suggested.

Unfortunately the scenario that you initially described cannot be implemented.  Basically when the TabControl's ItemsSource is populated with visual objects, those visual elements are placed inside the RadTabItem's Content. However, due to framework limitations, when the RadTabItem containers are generated to wrap the visual elements from the ItemsSource collection, the RadTabItems Header property isn't set. This is why when you place visual elements in the ItemsSource collection there are no Headers defined for those items and the HeaderTemplate bindings aren't executed.

As a workaround you can manually set the Header property of those RadTabItems that will wrap visual elements like your ItemControl:
public partial class MainWindow : Window
{
    public MainWindow()
    {
        DataContext = new MainWindowViewModel();
        InitializeComponent();
 
        tabControl.AddHandler(RadTabItem.LoadedEvent, new RoutedEventHandler(RadTabItem_Loaded));
    }
 
 
    private void RadTabItem_Loaded(object sender, RoutedEventArgs e)
    {
        RadTabItem item = (sender as RadTabControl).ItemContainerGenerator.ContainerFromIndex(0) as RadTabItem;
        item.Header = item.DataContext;
    }
}
However, when the RadTabItem.Header property is a visual element, in certain scenarios the GarbageCollector may not clean all its references due to framework limitations and this may lead to leaks.

Greetings,
Tina Stancheva
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
Tags
TabControl
Asked by
Maxim
Top achievements
Rank 1
Answers by
Tina Stancheva
Telerik team
Maxim
Top achievements
Rank 1
Share this question
or