如何使用已设置的StyleSsource样式

时间:2014-05-03 11:29:26

标签: wpf xaml listview binding

我的问题是如何在ItemsSource内引用Window我已设置的Style?我有以下ListViews

AppointmentOverview.xaml

    <ListView Grid.Column="1" Grid.Row="3" ItemsSource="{Binding Mov}"/>
    <ListView Grid.Column="1" Grid.Row="4" ItemsSource="{Binding Mon}"/>
    <ListView Grid.Column="2" Grid.Row="3" ItemsSource="{Binding Div}"/>
    <ListView Grid.Column="2" Grid.Row="4" ItemsSource="{Binding Din}"/>
    <ListView Grid.Column="3" Grid.Row="3" ItemsSource="{Binding Miv}"/>
    <ListView Grid.Column="3" Grid.Row="4" ItemsSource="{Binding Min}"/>
    <ListView Grid.Column="4" Grid.Row="3" ItemsSource="{Binding Dov}"/>
    <ListView Grid.Column="4" Grid.Row="4" ItemsSource="{Binding Don}"/>
    <ListView Grid.Column="5" Grid.Row="3" ItemsSource="{Binding Frv}"/>
    <ListView Grid.Column="5" Grid.Row="4" ItemsSource="{Binding Frn}"/>

正如您所看到的,每个ListView都有不同的ItemsSource,因此我无法通过ItemsSource设置Style。但他们都有相同的Style。此Style应包含Composite CollectionComposite Collection应包含此ItemsSource +一个Button。我的问题是如何告诉CollectionViewSource它应该使用已设置的ItemsSource?我的Styles位于不同的文件中。

Styles.xaml

<Style TargetType="{x:Type ListView}">
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <UniformGrid Rows="5" Columns="1"/>
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled"/>
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>        
</Style>

<Style TargetType="{x:Type ListViewItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListViewItem}">
                <Border BorderBrush="#5076A7" BorderThickness="1">
                    <Border.Background>
                        <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                            <GradientStop Color="#FFFFFF" Offset="0.0"/>
                            <GradientStop Color="#C0D3EA" Offset="1.0"/>
                        </LinearGradientBrush>
                    </Border.Background>
                    <StackPanel TextElement.FontFamily="Segoe UI" TextElement.FontSize="12">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="15"/>
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="*"/>
                            </Grid.RowDefinitions>
                            <TextBlock Padding="3,0,0,0" Text="{Binding Betreff}" TextTrimming="CharacterEllipsis" Grid.Column="0" Grid.Row="0"/>
                            <Button FontSize="7" Content="X" Grid.Column="1" Grid.Row="0" 
                                    Command="{Binding DataContext.DeleteButtonCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" 
                                    CommandParameter="{Binding ItemId}"/>
                        </Grid>
                        <TextBlock Padding="3,0,0,0" Text="{Binding Kunde}"/>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock FontWeight="Bold" Padding="3,0,0,0" Text="{Binding Ort}"/>
                            <TextBlock Padding="3,0,0,0" Text="("/>
                            <TextBlock Text="{Binding Alternative}"/>
                            <TextBlock Text=")"/>
                        </StackPanel>
                    </StackPanel>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <DataTrigger Binding="{Binding Betreff}" Value="Blocked">
            <Setter Property="Template" Value="{StaticResource BlockedListViewItem}"/>
        </DataTrigger>
    </Style.Triggers>
</Style>

1 个答案:

答案 0 :(得分:0)

您可以创建一个附加属性,该属性将保留初始集合,以避免与将在样式中注入的集合冲突。您必须创建一个新的DependencyObject类或在现有类中定义它:

public class Extensions : DependencyObject
{

    #region MyItemsSource

    /// <summary>
    /// MyItemsSource Attached Dependency Property
    /// </summary>
    public static readonly DependencyProperty MyItemsSourceProperty =
        DependencyProperty.RegisterAttached("MyItemsSource", typeof(IEnumerable), typeof(Extensions),
            new FrameworkPropertyMetadata((IEnumerable)null));

    /// <summary>
    /// Gets the MyItemsSource property. This dependency property 
    /// indicates ....
    /// </summary>
    public static IEnumerable GetMyItemsSource(DependencyObject d)
    {
        return (IEnumerable)d.GetValue(MyItemsSourceProperty);
    }

    /// <summary>
    /// Sets the MyItemsSource property. This dependency property 
    /// indicates ....
    /// </summary>
    public static void SetMyItemsSource(DependencyObject d, IEnumerable value)
    {
        d.SetValue(MyItemsSourceProperty, value);
    }

    #endregion


}

现在在XAML中,ListView将如下所示:

<ListView  local:Extensions.MyItemsSource="{Binding Items}" Style="{StaticResource ListBox_Style}"/>

要将ItemsSource实际绑定到CompositeCollection中的MyItemsSource属性,没有简单的解决方案。 compositeCollection不是Visual对象,甚至不是DependencyProperty,因此不能使用findAncestor绑定。在这种情况下,使用CollectionViewSource作为样式的资源将不起作用。

这里需要一些解决方法。一种可能性是使用转换器:

public class CollectionConverter : IValueConverter
{
    public ControlTemplate AdditionalControlTemplate { get; set; }

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {

        CompositeCollection cc = new CompositeCollection();

        //Add base ItemSource
        CollectionContainer cont = new CollectionContainer();
        cont.Collection = (IEnumerable)value;
        cc.Add(cont);

        //Add a control at the end
        if(AdditionalControlTemplate != null)
            cc.Add(new Control() { Template = AdditionalControlTemplate });

        return cc;

    }

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

此转换器获取源集合并将其注入CompositeCollection。然后使用可在转换器外指定的模板将控件添加到此集合中。所以你的按钮可以进入这个ControlTemplate。 ListView样式将如下所示:

<Style x:Key="ListBox_Style" TargetType="{x:Type ListView}">
    <Style.Resources>
        <!-- Control template for the object to be added at the end of the ListView -->
        <ControlTemplate x:Key="AdditionalButtonTemplate" TargetType="{x:Type Control}">
            <Button Content="Hello World!"/>
        </ControlTemplate>
        <local:CollectionConverter x:Key="CollectionConverter" AdditionalControlTemplate="{StaticResource AdditionalButtonTemplate}"/>
    </Style.Resources>

    <Setter Property="ItemsSource" Value="{Binding (local:Extensions.MyItemsSource), Converter={StaticResource CollectionConverter}, RelativeSource={RelativeSource Self}}"/>
</Style>

绕过CompositeCollection限制的更简单的解决方案是使用中间ItemsControl。因此,您将使用ItemsControl而不是ListView:

使用以下样式:

<Style x:Key="icListViewStyle" TargetType="{x:Type ItemsControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ItemsControl}">
                <ListView>
                    <ListView.Resources>
                        <CollectionViewSource x:Key="BaseItemsSource" Source="{Binding ItemsSource, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}, AncestorLevel=2}}"/>
                    </ListView.Resources>
                    <ListView.ItemsSource>
                        <CompositeCollection>
                            <CollectionContainer Collection="{Binding Source={StaticResource BaseItemsSource}}"/>
                            <Button Content="Hello World!"/>
                        </CompositeCollection>
                    </ListView.ItemsSource>
                </ListView>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

这里BaseItemsSource是ListView的资源,它是一个实际的可视对象,因此可以在绑定中解析RelativeSource。