none
WPF: Отступы для первого и последнего элементов списка RRS feed

  • Вопрос

  • Есть ItemsControl. Необходимо для первого и последнего элементов сделать отличные от других элементов Margin-ы. Можно ли это сделать красиво?

    В голову приходит много способов, но все они сводятся к тому, чтобы во ViewModel выделить эти элементы и их отдельно обработать. Хочется какое-нибудь более красивое решение. В css есть простое решение: ":first-child". Очень хочется что-то подобное и тут.

    6 февраля 2012 г. 13:57
    Отвечающий

Ответы

Все ответы

  • Здравсвтвуйте.

    Может вас устроит решение со stackoverflow - How to apply different styles to ListBox header and item


    Для связи [mail]

    • Помечено в качестве ответа Anton.MaksimovEditor 8 февраля 2012 г. 8:05
    7 февраля 2012 г. 9:13
  • > Есть ItemsControl. Необходимо для первого и последнего элементов сделать отличные от других элементов Margin-ы.

    <Window x:Class="WpfApplication3.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" FontSize="16" Width="300" Height="400" 
            xmlns:app="clr-namespace:WpfApplication3">
        <StackPanel>
            <ItemsControl ItemsSource="{Binding}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Id}">
                            <TextBlock.Margin>
                                <MultiBinding Converter="{app:MarginConverter}">
                                    <Binding RelativeSource="{RelativeSource AncestorType=ItemsControl}" Path="Items" />
                                    <Binding RelativeSource="{RelativeSource Self}" Path="DataContext" />
                                </MultiBinding>
                            </TextBlock.Margin>
                        </TextBlock>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </StackPanel>
    </Window>
    using System;
    using System.Globalization;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Markup;
    
    namespace WpfApplication3
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                this.DataContext =
                    from x in Enumerable.Range(0, 5) select new { Id = x, Value = "v" + x, Note = "n" + x };
            }
        }
    
        class MarginConverter : MarkupExtension, IMultiValueConverter
        {
            public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
            {
                var ic = values[0] as ItemCollection;
                var dc = values[1];
    
                var ret = new Thickness();
                var i = ic.IndexOf(dc);
                if (i == 0 || i == ic.Count - 1) ret.Left = 20;
    
                return ret;
            }
            public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
            {
                throw new NotImplementedException();
            }
            public override object ProvideValue(IServiceProvider serviceProvider) { return this; }
        }
    }

    7 февраля 2012 г. 16:28
  • а для DataGrid так:

     
    <Window x:Class="WpfApplication3.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" FontSize="16" Width="300" Height="400" 
            xmlns:app="clr-namespace:WpfApplication3">
        <StackPanel>
            <DataGrid ItemsSource="{Binding}" ColumnWidth="*" HeadersVisibility="Column">
                <DataGrid.CellStyle>
                    <Style TargetType="DataGridCell">
                        <Setter Property="Margin">
                            <Setter.Value>
                                <MultiBinding Converter="{app:CellMarginConverter}" ConverterParameter="0">
                                    <Binding RelativeSource="{RelativeSource Self}" />
                                    <Binding RelativeSource="{RelativeSource AncestorType=DataGridRow}" />
                                    <Binding RelativeSource="{RelativeSource AncestorType=DataGrid}" />
                                </MultiBinding>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </DataGrid.CellStyle>
            </DataGrid>
        </StackPanel>
    </Window>
    using System;
    using System.Globalization;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Markup;
    
    namespace WpfApplication3
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                this.DataContext =
                    from x in Enumerable.Range(0, 5) select new { Id = x, Value = "v" + x, Note = "n" + x };
            }
        }
    
        class CellMarginConverter : MarkupExtension, IMultiValueConverter
        {
            public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
            {
                var c = values[0] as DataGridCell;
                var r = values[1] as DataGridRow;
                var d = values[2] as DataGrid;
                var ret = r.Margin;
                if (c.Column.DisplayIndex.ToString() == parameter.ToString())
                {
                    var ri = r.GetIndex();
                    if (ri == 0 || ri == d.Items.Count - 1)
                        ret.Left += 20;
                }
                return ret;
            }
            public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
            {
                throw new NotImplementedException();
            }
            public override object ProvideValue(IServiceProvider serviceProvider) { return this; }
        }
    }

    7 февраля 2012 г. 16:29
  • Для первого элемента как раз то что нужно, спасибо :)

    Возможно что-то подобное найду и для последнего элемента.

    8 февраля 2012 г. 8:06
    Отвечающий
  • Спасибо за помощь, но решение не подойдет если придется менять не только Margin, а весь стиль и не хардкодить его, а использовать ресурс.

    P.S. в вопросе был только Margin, но всегда хочется что-то более универсальное, простое и переиспользуемое.

    8 февраля 2012 г. 8:21
    Отвечающий