Windows Phone 8.1中ListView中行的交替颜色

时间:2014-12-22 17:52:47

标签: listview windows-runtime windows-phone-8.1 listviewitem

我创建了一个Windows Phone 8.1运行时应用程序。

我正在使用ListView控件。

我希望替换每个背景行颜色。

搜索后,我发现此链接a previous answer

但这会给标记带来错误。一方面,没有“AlternationCount”#39;属性。我假设这是因为它不是SilverLight而是RT?

如果有人可以给我发送链接,因为我正在寻找一个简单的例子。更好的是一个简单的代码示例。

5 个答案:

答案 0 :(得分:6)

我知道这个问题已经有了一些很好的答案,但我只想提出一个更多的想法,我认为这个想法有点难以实现,但更容易使用。

此解决方案需要ListView ItemContainerStyleSelector的帮助和行为SDK(XAML)Behavior

基本上,我创建的AlternatingColorItemContainerStyleSelector行为允许您指定两种SolidColorBrush颜色。它概括了使用两个不同的ItemContainerStyleSelector创建Style以及为每个SolidColorBrush分配相应的Style的逻辑。

一旦你有了这种行为,使用它非常简单 - 我只需要将它拖放到Expression Blend中的ListView并指定两种颜色即可!

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()
        {
        }
    }
}

有一点需要注意的是,删除商品不会更新所有其他商品&#39;颜色(仅仅因为其他项目的SelectStyleCore未被调用),添加项目将会。但在你的情况下,这应该足够了。

答案 1 :(得分:5)

我的建议是将 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 :(得分:2)

WPF是唯一支持&#34; AlternationCount&#34; - Windows Phone,Silverlight和RT都没有。

您可能会发现最简单的解决方案就是添加一个&#34;索引&#34;或者&#34; IsOdd&#34;您的行模型的属性。您可以绑定到该属性,使用转换器根据索引返回适当的画笔/颜色。

一种更简单的方法是绑定到使用静态变量跟踪索引的转换器,如下所示。但是,如果您使用项目虚拟化(除非您只有少数项目,您可能会这样做),这种方法会出现故障:UI元素的延迟创建会导致索引无序分配,并且您结束连续的行显示相同的颜色。

<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);
    }
}

答案 3 :(得分:2)

对我而言,最简单的方法是:

    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);
        }
    }

只需将您连接到ListView的ContainerContentChanging-Event即可。我不知道你的名单是否合适,但正常情况下它的效果非常好。

您甚至可以实现自己的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);
        }
    }
}

答案 4 :(得分:0)

感谢您的回复 - 非常感谢。我有另一个我想提出的解决方案,我将其发布在此处供人们评论。

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;
 }

编辑 - 罗马斯编辑

如果您愿意,您可以随时使用代码,但是您的解决方案不是那么通用,在更改收集时必须始终运行并且可能有其他问题。我把这个评论作为你的答案的编辑,因此上面的代码可能会简化,它看起来像这样(在答案中看起来更好):

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];
}