Обязательная область - стили и шаблоны - PullRequest
0 голосов
/ 21 сентября 2010

У меня есть пользовательский ItemsControl в моем проекте, и я пытаюсь написать для него стиль, который объединяет статический список элементов со списком элементов в свойстве зависимости в самом элементе управления.

Вот соответствующий XAML в моем Словаре ресурсов:

<x:Array Type="{x:Type System:Object}" x:Key="Static_CloudItems">
    <Button>One</Button>
    <Button>Two</Button>
    <Button>Three</Button>
</x:Array>

<Style TargetType="{x:Type ControlsBase:CloudControl}" x:Key="BasicCloudStyle">
    <Setter Property="ItemsSource">
        <Setter.Value>
            <CompositeCollection>
                <CollectionContainer Collection="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ControlsBase:CloudControl}}, Path=CloudItems}" />
                <CollectionContainer Collection="{StaticResource Static_CloudItems}" />
            </CompositeCollection>
        </Setter.Value>
    </Setter>
</Style>

И затем соответствующий код в моих элементах управления / окнах / чем-либо:

<ControlsBase:CloudControl Style="{DynamicResource BasicCloudStyle}">
    <ControlsBase:CloudControl.CloudItems>
        <x:Array Type="{x:Type System:Object}">
            <Button>Four</Button>
            <Button>Five</Button>
        </x:Array>
    </ControlsBase:CloudControl.CloudItems>
</ControlsBase:CloudControl>

Идея в том, что стильследует комбинировать статические элементы с любыми элементами, определенными в издании элемента управления для каждого экземпляра.

Моя проблема заключается в том, что приведенное выше связывание не работает (и я тоже понял, почему!) Так что мне нуженспособ привязки к родителю стиля, но так как сеттер не находится в визуальном / логическом дереве, просто свойство, которое я немного озадачен тем, как действовать дальше.

1 Ответ

0 голосов
/ 21 сентября 2010

Как насчет реализации IValueConverter, который создает правильную CompositeCollection для элемента управления за кулисами? Смотрите образец ниже:

XAML:

<Window x:Class="StackOverflow.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:System="clr-namespace:System;assembly=mscorlib"
        xmlns:local="clr-namespace:StackOverflow"
        Title="MainWindow" Height="350" Width="525"
        x:Name="window">
    <Window.Resources>
        <x:Array Type="{x:Type System:Object}" x:Key="Static_CloudItems">
            <Button>One</Button>
            <Button>Two</Button>
            <Button>Three</Button>
        </x:Array>

        <local:MyItemsSourceConverter x:Key="myConverter"/>
        <Style TargetType="{x:Type local:MyControl}" x:Key="BasicCloudStyle">
            <Setter Property="ItemsSource" 
                    Value="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource myConverter}}"/>
        </Style>
    </Window.Resources>

    <local:MyControl Style="{StaticResource BasicCloudStyle}" >
        <local:MyControl.InstanceItems>
            <System:String>Item1</System:String>
            <System:String>Item2</System:String>
            <System:String>Item3</System:String>
        </local:MyControl.InstanceItems>
    </local:MyControl>
</Window>

Code-Behind:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }
}

public class MyControl : ListBox 
{
    public ObservableCollection<object> InstanceItems
    {
        get { return (ObservableCollection<object>)GetValue(InstanceItemsProperty); }
        set { SetValue(InstanceItemsProperty, value); }
    }

    // Using a DependencyProperty as the backing store for InstanceItems.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty InstanceItemsProperty =
        DependencyProperty.Register("InstanceItems", typeof(ObservableCollection<object>), 
        typeof(MyControl), new UIPropertyMetadata(new ObservableCollection<object>()));
}

public class MyItemsSourceConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        MyControl mc = value as MyControl;
        if (mc != null)
        {
            CompositeCollection cc = new CompositeCollection();

            CollectionContainer container1 = new CollectionContainer();
            BindingOperations.SetBinding(container1, CollectionContainer.CollectionProperty,
                new Binding()
                {
                    Source = mc,
                    Path = new PropertyPath("InstanceItems")
                });
            cc.Add(container1);

            CollectionContainer container2 = new CollectionContainer()
            {
                Collection = mc.FindResource("Static_CloudItems") as Array
            };

            cc.Add(container2);

            return cc;
        }
        return null;
    }

    public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new System.NotImplementedException();
    }

    #endregion
}
...