Переменные цвета строк в ListView в Windows Phone 8.1

Я создал приложение под управлением Windows Phone 8.1.

Я использую элемент управления ListView.

Я хочу изменить каждый цвет строки фона.

После поиска я нашел эту ссылку предыдущий ответ.

Но это дает ошибки в разметке. Во-первых, нет свойства AlternationCount. Я предполагаю это потому, что это не SilverLight, а RT?

Если кто-нибудь может отправить мне ссылку, поскольку я изо всех сил пытаюсь найти простой пример. даже лучше использовать простой пример кода.

Ответ 1

Мое предложение - использовать класс Converter с дополнительными DependencyProperties. Когда вы инициализируете конвертер, вы определяете, к какой коллекции элементов он относится, и список альтернативных кистей для фона. Он может выглядеть следующим образом:

public class AlternateConverter : DependencyObject, IValueConverter
{
    public List<SolidColorBrush> AlternateBrushes
    {
        get { return (List<SolidColorBrush>)GetValue(AlternateBrushesProperty); }
        set { SetValue(AlternateBrushesProperty, value); }
    }

    public static readonly DependencyProperty AlternateBrushesProperty =
        DependencyProperty.Register("AlternateBrushes", typeof(List<SolidColorBrush>), 
        typeof(AlternateConverter), new PropertyMetadata(new List<SolidColorBrush>()));

    public object CurrentList
    {
        get { return GetValue(CurrentListProperty); }
        set { SetValue(CurrentListProperty, value); }
    }

    public static readonly DependencyProperty CurrentListProperty =
        DependencyProperty.Register("CurrentList", typeof(object),
        typeof(AlternateConverter), new PropertyMetadata(null));

    public object Convert(object value, Type targetType, object parameter, string language)
    { return AlternateBrushes[(CurrentList as IList).IndexOf(value) % AlternateBrushes.Count]; }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    { throw new NotImplementedException(); }
}

Как только вы определили и создали список альтернативных кистей:

// somewhere in your DataContext
private List<SolidColorBrush> brushes = new List<SolidColorBrush> { new SolidColorBrush(Colors.Red), new SolidColorBrush(Colors.Blue) };
public List<SolidColorBrush> Brushes { get { return brushes; } }

Вы можете использовать его следующим образом:

<ListView x:Name="myList" ItemsSource={Binding MyItems}>
  <ListView.Resources>
    <local:AlternateConverter CurrentList="{Binding ElementName=myList, Path=ItemsSource}" 
                                      AlternateBrushes="{Binding Brushes}"
                                      x:Key="AlternateConverter"/>
  </ListView.Resources>
  <ListView.ItemTemplate>
     <DataTemplate>
       <Border Background="{Binding Converter={StaticResource AlternateConverter}}">
          <!-- your itemtemplate -->
       </Border>
     </DataTemplate>
  </ListView.ItemTemplate>
</ListView>

Это решение должно работать, хотя у него может быть проблема, когда у вас есть IList типов значений. Также здесь не должно быть проблем с отложенным созданием, поскольку он возвращает индекс непосредственно из списка.

Ответ 2

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

Для этого решения потребуется помощь от ListView ItemContainerStyleSelector и a Behavior из SDK поведения (XAML).

В принципе, это поведение AlternatingColorItemContainerStyleSelector, которое я создал, позволяет вам указать два цвета SolidColorBrush. Он инкапсулирует логику создания ItemContainerStyleSelector двумя разными Style, а также назначает соответствующий SolidColorBrush для каждого Style.

Как только у вас есть поведение на месте, его использование чрезвычайно просто - мне нужно было только перетащить его на ListView в Expression Blend и указать два цвета и это!

enter image description here

Здесь поведение.

namespace Behaviors
{
    public class AlternatingColorItemContainerStyleSelector : StyleSelector
    {
        private Style _oddStyle = new Style { TargetType = typeof(ListViewItem) }, _evenStyle = new Style { TargetType = typeof(ListViewItem) };
        public Style OddStyle { get { return _oddStyle; } }
        public Style EvenStyle { get { return _evenStyle; } }

        protected override Style SelectStyleCore(object item, DependencyObject container)
        {
            var listViewItem = (ListViewItem)container;
            var listView = GetParent<ListView>(listViewItem);

            var index = listView.IndexFromContainer(listViewItem);

            if (index % 2 == 0)
            {
                return this.EvenStyle;
            }
            else
            {
                return this.OddStyle;
            }
        }

        public static T GetParent<T>(DependencyObject child) where T : DependencyObject
        {
            while (!(child is T))
            {
                child = VisualTreeHelper.GetParent(child);
            }

            return (T)child;
        }
    }

    public class ListViewAlternatingColorBehavior : DependencyObject, IBehavior
    {
        public DependencyObject AssociatedObject { get; set; }

        public Style SharedItemContainerStyle { get; set; }

        #region colors dp

        public SolidColorBrush OddBrush
        {
            get { return (SolidColorBrush)GetValue(OddBrushProperty); }
            set { SetValue(OddBrushProperty, value); }
        }

        public static readonly DependencyProperty OddBrushProperty =
            DependencyProperty.Register("OddBrush", typeof(SolidColorBrush), typeof(ListViewAlternatingColorBehavior), new PropertyMetadata(null));

        public SolidColorBrush EvenBrush
        {
            get { return (SolidColorBrush)GetValue(EvenBrushProperty); }
            set { SetValue(EvenBrushProperty, value); }
        }

        public static readonly DependencyProperty EvenBrushProperty =
            DependencyProperty.Register("EvenBrush", typeof(SolidColorBrush), typeof(ListViewAlternatingColorBehavior), new PropertyMetadata(null));

        #endregion

        public void Attach(DependencyObject associatedObject)
        {
            this.AssociatedObject = associatedObject;

            this.ApplyItemContainerStyleSelectors();
        }

        private void ApplyItemContainerStyleSelectors()
        {
            var itemContainerStyleSelector = new AlternatingColorItemContainerStyleSelector();

            if (this.SharedItemContainerStyle != null)
            {
                itemContainerStyleSelector.OddStyle.BasedOn = this.SharedItemContainerStyle;
                itemContainerStyleSelector.EvenStyle.BasedOn = this.SharedItemContainerStyle;
            }

            itemContainerStyleSelector.OddStyle.Setters.Add(new Setter { Property = Control.BackgroundProperty, Value = this.OddBrush });
            itemContainerStyleSelector.EvenStyle.Setters.Add(new Setter { Property = Control.BackgroundProperty, Value = this.EvenBrush });

            var listView = (ListView)this.AssociatedObject;
            listView.ItemContainerStyleSelector = itemContainerStyleSelector;
        }

        public void Detach()
        {
        }
    }
}

Следует отметить, что удаление элементов не будет обновлять все цвета других элементов (просто потому, что SelectStyleCore других элементов не будет вызываться), добавив элементы. Но в вашем случае этого должно быть достаточно.

Ответ 3

WPF - единственная инфраструктура, поддерживающая "AlternationCount" - ни Windows Phone, ни Silverlight, ни RT.

Вы можете обнаружить, что самым простым решением является просто добавить свойство "Index" или "IsOdd" в вашу модель строки. Вы можете просто привязать это свойство, используя конвертер, чтобы вернуть соответствующую кисть/цвет в зависимости от индекса.

Один более простой подход заключается в привязке к конвертеру, который отслеживает индекс, используя статическую переменную, как показано ниже. Однако, если вы используете виртуализацию элементов (что вы, вероятно, делаете, если у вас есть только несколько элементов), тогда этот подход сталкивается с сбоями: отложенное создание элементов пользовательского интерфейса приводит к тому, что индексы становятся назначенными вне порядка, и вы заканчиваете с последовательными рядами, отображающими один и тот же цвет.

<Border Background="{Binding Converter={StaticResource AlternatingIndexConverter}}">

public class AlternatingIndexConverter : IValueConverter
{
    private static int _index;

    public Brush Even { get; set; }
    public Brush Odd { get; set; }

    public object Convert(...)
    {
        return (_index++ % 2 == 0 ? Even : Odd);
    }
}

Ответ 4

Для меня самый гладкий способ сделать это:

    private void ListView_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
    {
        if (args.ItemIndex%2 != 0)
        {
            args.ItemContainer.Background = new SolidColorBrush(Colors.Aqua);
        }
        else
        {
            args.ItemContainer.Background = new SolidColorBrush(Colors.White);
        }
    }

Просто подключите вас к ContainerContentChanging-Event вашего ListView. Я не знаю, работает ли это, когда ваш курорт будет в вашем списке, но для нормального случая он работает очень хорошо.

Вы даже можете реализовать свой собственный ListView, чтобы вы могли использовать его столько, сколько хотите. С помощью правильных свойств вы также можете отредактировать его в файле xaml. Например, присваивание # FFFF0000 (ARGB).

public class BackgroundAlternatingListView : ListView
{
    private Color _startColor = Colors.White;
    private Color _secondColor = new Color { A = 255, R = 198, G = 198, B = 198 };

    public Color StartColor
    {
        get { return _startColor; }
        set { _startColor = value; }
    }

    public Color SecondColor
    {
        get { return _secondColor; }
        set { _secondColor = value; }
    }


    public BackgroundAlternatingListView()
    {
        ContainerContentChanging += BackgroundAlternatingListView_ContainerContentChanging;
    }

    void BackgroundAlternatingListView_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
    {
        if (args.ItemIndex % 2 != 0)
        {
            args.ItemContainer.Background = new SolidColorBrush(_secondColor);
        }
        else
        {
            args.ItemContainer.Background = new SolidColorBrush(_startColor);
        }
    }
}

Ответ 5

Спасибо за ваши ответы - очень ценю. У меня есть другое решение, которое я хотел бы предложить, и я размещаю его здесь, чтобы люди могли комментировать.

lvwPremises.Items.Clear();
bool toggle = false;
foreach (Premise premise in Shared.Premises)
{
     ListViewItem item = new ListViewItem();
     item.Content = premise.PremiseName;
     if (toggle)
     {
         item.Background = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 223, 240, 216));
     }
     else
     {
         item.Background = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 208, 233, 198));
     }
     lvwPremises.Items.Add(item);
     toggle = !toggle;
 }

ИЗМЕНИТЬ - Romasz

Вы всегда можете играть в коде, если хотите, но тогда ваше решение не так универсально, его нужно будет запускать всегда, когда вы меняете коллекцию и могут иметь другие проблемы. Я поместил этот комментарий в качестве редактирования вашего ответа, поэтому приведенный выше код может быть упрощен, и он может выглядеть так (выглядит более приятным в ответе):

private void ColorBackgrounds(ListView list, IList<SolidColorBrush> backgrounds)
{
    for (int i = 0; i < list.Items.Count; i++)
        (list.ContainerFromIndex(i) as ListViewItem).Background = backgrounds[i % backgrounds.Count];
}