1

I have a CustomTabItem in a custom controls library. When I explicitly use it in xaml or in code, it works. When I use the binding to ViewModel (CaliburnMicro) instead of my control, the standard TabItem is used. How to specify the use of CustomTabItem in xaml?
I tried to specify DataType = "{x:Type adc:ActorTabItem}" - did not work.

I tried to specify DataType="{x:Type adc:CustomTabItem}" - did not work.

        <adc:TabControl ItemsSource="{Binding Pages}" Grid.Row="1">
            <TabControl.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Name}"></TextBlock>
                </DataTemplate>
            </TabControl.ItemTemplate>

            <adc:TabControl.ContentTemplate>
                <DataTemplate>
                    <ContentControl cal:View.Model="{Binding}" />
                </DataTemplate>
            </adc:TabControl.ContentTemplate>
        </adc:TabControl>
Oram
  • 1,500
  • 2
  • 18
  • 22
Yury Yatskov
  • 95
  • 1
  • 6
  • You may need to subclass the TabControl and override its [`ItemContainerGenerator` property](https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.itemscontrol.itemcontainergenerator?view=netframework-4.8), to return your own ItemContainerGenerator object that creates instances of your subclass. Unfortunately, WPF doesn't seem to have provided a way to plug that in without subclassing the parent (this is the same for ListBox, ItemsControl, etc.). – 15ee8f99-57ff-4f92-890c-b56153 May 08 '19 at 19:34
  • Thank you. Considered the inside of the ItemContainerGenerator property and the methods ContainerFromItem (Object) and ContainerFromIndex (Int32). Inside a common mechanism without reference to the class TabItem. Change did not become this property. This path led me to the GetContainerForItemOverride and IsItemItsOwnContainerOverride methods of the TabControl class. I redefined these methods in the subclass and I received a positive result. Below is the code: – Yury Yatskov May 13 '19 at 08:58
  • protected override bool IsItemItsOwnContainerOverride(object item) { return (item is ActorTabItem); } protected override DependencyObject GetContainerForItemOverride() { return new ActorTabItem(); } – Yury Yatskov May 13 '19 at 09:01
  • Next, I ran into another problem where my CustomTabItem has no parent, and the children (items) for TabControl have a view model. But it will be another question if I do not decide. – Yury Yatskov May 13 '19 at 09:44
  • 1) Please add your classes to your question so I can figure out what the parent thing is all about. 2) Children having a viewmodel should not be a problem at all (except for [this issue that you may not have run into yet](https://stackoverflow.com/questions/9794151/stop-tabcontrol-from-recreating-its-children)). Why do you think the viewmodel is an issue? – 15ee8f99-57ff-4f92-890c-b56153 May 13 '19 at 13:33
  • 1) For more understanding, I created an example and located here https://github.com/YuryYatskov/PeopleDemo . – Yury Yatskov May 13 '19 at 20:34
  • 2) Previously, I did not encounter this problem, but it seems that I now have it.In my example, I added the functionality of dragging bookmarks in the library's program code.When I do not use the binding in ItemsSource then everything works. When I use binding to view model, then dragging does not work. Therefore, the view model is an issue. – Yury Yatskov May 13 '19 at 20:35
  • I think I need to inform the library about the need for shuffling. At the application level, implement a change in an ItemsSource. Possible to override the ItemsSource property. – Yury Yatskov May 13 '19 at 20:38
  • Overriding ItemsSource is not a good idea. You don’t have any problems with ItemsSource. What is a “Binding in ItemsSource”? I’ll have to look at your drag and drop code. Dragging and dropping collection items is a solved problem, if I correctly understand what you’re doing. – 15ee8f99-57ff-4f92-890c-b56153 May 13 '19 at 21:21
  • Your drop is broken if you’re creating tab items from a collection of viewmodels bound to TabControl.ItemsSource. Do not touch Items. Always, when there’s a bound collection, alter the collection itself. Add, remove, reorder the viewmodels. Let the TabControl (or ComboBox or whatever) update UI accordingly. See: https://stackoverflow.com/a/48064086/424129 – 15ee8f99-57ff-4f92-890c-b56153 May 13 '19 at 21:39
  • Yes, I can change the ItemsSource collection itself. Changed the example, the ItemsSource upcasted to the IList. It works. Please give a short answer to this question so that I can mark it as correct. Thank! – Yury Yatskov May 14 '19 at 18:48

2 Answers2

0

You've got two things going on here:

  1. You'll need to subclass TabControl and override its ItemContainerGenerator property to generate your MyTabItem type instead of its own. Unfortunately, you can't do that without subclassing. There's nothing analagous to ItemsPanelTempalate for the items themselves.

  2. If you're binding TabControl.ItemsSource to a collection, the way to reorder the child items in the tab control is to reorder the bound collection, and then let TabControl handle updating the UI. The actual collection has to be an ObservableCollection for this to work, but it should be so in any case. The declared type of TabControl.ItemsSource is System.Collections.IEnumerable, but you can cast it to System.Collections.IList in your drop handler, and use that to reorder the collection. It will work, and the appropriate notifications will be raised.

0

You can do what you want easily. Just override the GetContainerForItemOverride method as following

public class TabControlEx : TabControl
{

    protected override DependencyObject GetContainerForItemOverride()
    {
        return new TabItemEx();
    }
}
  • Yes, I did it and it worked. For completeness, I also redefined ```lang-csharp protected override bool IsItemItsOwnContainerOverride(object item) => item is TabItemEx; ``` – Yury Yatskov Dec 09 '20 at 06:29