Binding Scope - Styles & Templates
I've got a custom ItemsControl
in my project and I'm trying to write a style for it that combines a static list of items with a list of items on a Dependency Property on the control itself.
Here is the respective XAML in my Resource Dictionary:
<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>
And then the respective code in my controls/windows/whatever:
<ControlsBas开发者_StackOverflow社区e: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>
The Idea is that the style should combine the static elements with whatever elements are defined on the per-instance edition of the control.
My issue is, The binding above does not work (and I've realized why too!) So I need a way to be able to bind to the style's parent, but since the setter isn't in the visual/logical tree, just a property I'm a bit puzzled about how to proceed.
How about implementing an IValueConverter that builds the correct CompositeCollection for the Control behind the scenes? See sample below:
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
}
精彩评论