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

11

我已经创建了一个运行在Windows Phone 8.1平台的应用程序。

我正在使用ListView控件。

我希望交替设置每个背景行的颜色。

在搜索后,我找到了这个链接先前的回答

但是这会在标记中产生错误。首先没有'AlternationCount'属性。 我假设这是因为它不是SilverLight而是RT?

如果有人能够给我发送一个链接,因为我正在努力寻找一个简单的示例。更好的是,提供一个简单的代码示例将不胜感激。

5个回答

6
我知道已经有一些好的答案针对这个问题,但我想再提出一个想法,我认为它更难实现但更容易使用。
这个解决方案需要依赖于`ListView`的`ItemContainerStyleSelector`和来自行为SDK(XAML)的`Behavior`。
基本上,我创建的这个`AlternatingColorItemContainerStyleSelector`行为允许您指定两个`SolidColorBrush`颜色。它封装了创建具有两种不同样式和将相应的`SolidColorBrush`分配给每个`Style`的`ItemContainerStyleSelector`的逻辑。
一旦您完成了该行为,使用起来非常简单 - 我只需要在Expression Blend中将其拖放到`ListView`上并指定两种颜色即可!
下面是该行为的代码。
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 不会被调用),而添加项目则会。但在您的情况下,这应该已经足够了。


2
嗨,我从未想过我会得到这么好的答案来回答这个问题。谢谢! - Andrew Simpson

5
我的建议是使用一个带有附加DependencyPropertiesConverter类。当你初始化转换器时,你需要定义它所引用的项集合以及背景的备选画笔列表。例如,它可以像这样:
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,则可能会出现问题。此外,在延迟创建方面不应该有问题,因为它直接从列表中检索索引。

你有关于你在 http://stackoverflow.com/questions/28621914/force-redraw-on-listview-in-windows-store-app 的代码问题的答案吗? - An Hoa
如果您需要对列表进行排序或交换项目,则此解决方案将不起作用。 - Jens Marchewka
@ElMarchewko 是的,上面的代码只有在列表被创建时才能工作。如果您需要执行更高级的操作,则该方法将需要进行一些改进。 - Romasz
@Romasz 但是怎么做呢?在项目绑定中触发更新是否可能? - Jens Marchewka
@ElMarchewko 在上述情况下,背景仅在项目创建时设置。我不确定在您的情况下最简单的解决方案是否是只需在项目负责数字的附加属性中添加,则可以将其与backgroundcolor绑定,并在每次需要时调用它。 - Romasz

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事件挂钩即可。我不知道当您重新排序列表时它是否有效,但在正常情况下,它非常有效。

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

2
WPF是唯一支持"AlternationCount"的框架--Windows Phone、Silverlight和RT都不支持。你可能会发现最简单的解决方案就是在行模型中添加一个"Index"或"IsOdd"属性。然后,你可以绑定到该属性,使用转换器根据索引返回适当的画刷/颜色。另外一种更简单的方法是绑定到一个转换器,该转换器使用静态变量跟踪索引,如下所示。但是,如果你使用了项虚拟化(除非只有少数项),那么这种方法会遇到故障: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);
    }
}

嗨,感谢您发布这个答案。它接近我想要的,但另一个答案给了我更多。谢谢。 - Andrew Simpson

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

编辑 - 由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];
}

1
个人而言,我会避免直接使用 ListViewItem - Justin XL
1
我已经编辑了你的答案并在其中添加了一些小注释 - 当然,你可以像这样做,一切都可以通过代码进行更改。但是当你更改列表并添加一些项目时,你会怎么做呢? - Romasz
1
@JustinXL 谢谢你再次激发我的思考 :) - Andrew Simpson
1
好的,这是正常的ListView数据绑定流程 - 您定义一个ObservableCollection<Premise>,并将ListViewItemsSource绑定到它。然后在ListViewItemTemplate中,一个TextBlock将其Text属性绑定到PremiseNameListViewItem是包装ItemTemplate的东西。通常情况下,您只会在xaml中更新ListViewItem的样式,以便具有不同的外观和感觉。希望这可以稍微澄清一下! - Justin XL
1
是的,确实可以。谢谢。 (顺便说一下,我喜欢你的应用程序) - Andrew Simpson
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接