Динамически создаваемые TabItems с несколькими привязками и RelativeSource -> UnsetValue

#wpf #xaml #dynamic #tabitem #multibinding

#wpf #xaml #динамический #tabitem #многозадачность

Вопрос:

В моем приложении WPF я хочу динамически создавать TabItems в многоразовом UserControl, содержащем TabControl.

ItemsSource элемента TabControl привязан к экземпляру ObservableCollection через стандартную привязку к данным.

Я создаю элементы табуляции, подобные этому, ПОСЛЕ InitializeComponent() того, как был вызван!

 // ...
int itemCount = 0;
TabItem it = null;

it = new TabItem();
it.Header = "Sicherungen   Relais";
tabItemList.Insert(itemCount  , it);            

it = new TabItem();
it.Header = "Lage der Bauteile";
tabItemList.Insert(itemCount  , it);

it = new TabItem();
it.Header = "Schaltpläne";
tabItemList.Insert(itemCount  , it);

it = new TabItem();
it.Header = "Tipps   Tricks";
tabItemList.Insert(itemCount  , it);
 

Хорошей новостью является то, что элементы действительно добавляются в TabControl с их соответствующими заголовками.

Теперь проблема возникает, когда WPF пытается применить к ним стиль ПОСЛЕ того, как окно стало видимым!

У меня есть этот стиль по умолчанию для TabItems:

 <Style TargetType="{x:Type TabItem}"
       BasedOn="{StaticResource TISTabItem}">
    <Setter Property="Width">
        <Setter.Value>
            <MultiBinding Converter="{StaticResource convCategoryTabWidthConverter}">
                <Binding RelativeSource="{RelativeSource AncestorType={x:Type TabControl}, Mode=FindAncestor}" />
                <Binding RelativeSource="{RelativeSource AncestorType={x:Type TabControl}, Mode=FindAncestor}"
                         Path="ActualWidth" />
            </MultiBinding>
        </Setter.Value>
    </Setter>
</Style>
 

И преобразователь:

 public class CategoryTabWidthConverter : IMultiValueConverter
{

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values == null || values.Count() < 1)
            throw new ArgumentException("Values array passed is invalid.", "values");

        if(values[0] == DependencyProperty.UnsetValue)
        {
            return 0; // Added for breakpoint. Bailing out here!!!
        }

        TabControl tabCtrl = values[0] as TabControl;
        Double w = (tabCtrl.ActualWidth / tabCtrl.Items.Count);
        w = (w <= 1) ? 0.0 : (w - 1);
        return w;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
 

Замечания: я использую этот конвертер и стиль в двух других местах, где TabItems статически добавляются в XAML! В этих случаях все работает нормально!

Однако, когда TabItems добавляются динамически, оба, TabControl RelativeSource и его ActualWidth оцениваются DependencyProperty.UnsetValue как .

Я ожидаю некоторых логических ошибок, с которыми я столкнулся здесь.

Когда применяются стили? До того, как TabItems будут правильно добавлены во внутренние деревья или после? У кого-нибудь есть идеи о том, что я здесь делаю не так?

Я продолжу расследование и заранее благодарю всех вас за вашу помощь.

Ответ №1:

Решил это сам. Проблема заключалась в том, что я забыл, что элементы ItemsSource будут перенесены в экземпляр TabItem.

TabItem внутри TabItem на самом деле не имеет смысла.

Прямая вставка их в TabControl.Элементы заставили его работать на удивление.