如何更改其索引与ViewModel中的更改值匹配的特定ListViewItem的背景?

时间:2016-11-03 13:23:44

标签: c# wpf xaml listview data-binding

我有一个ListView,其ItemsSource设置为我的ViewModel的集合属性。 ViewModel上还有一个属性,比如'CurrentIndex',它随着代码的运行而变化。由于这种变化,我只想要ListViewItem,其ListView中与“CurrentIndex”匹配的索引会发生变化,比如说它的背景会改变颜色。当'CurrentIndex'更改时,我希望先前引用的ListViewItem被“重置”,即其背景更改为先前的颜色。有谁知道我怎么做到这一点?

我想过利用ListView的SelectedIndex属性,但这不起作用,因为用户可以单击ListView并更改选择,从而更改错误项目的背景。

ListViewItems通过XAML中的ItemTemplate进行模板化。

希望这是有道理的。

非常感谢您的任何帮助。

2 个答案:

答案 0 :(得分:3)

这是另一种方法。您从a behavior that applies to WPF container controls like Grid, StackPanel, etc., and gives each of the children an attached ChildIndex property开始。然后在ItemContainerStyle的{​​{1}}中添加ListBox,其使用DataTrigger和多值转换器来比较每个MultiBinding的{​​{1}} ListBoxItem 1}}到viewmodel上的ChildIndex属性。

将行为应用于HighlightIndex本身会更方便(实际上,您希望将其应用于ListBox的祖先类ListBox),但实际上,您可以在不在列表框中的内容上使用它。

XAML:

ItemsControl

行为:

<ListBox
    ItemsSource="{Binding Items}"
    >
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel 
                hbo:PanelBehaviors.IsChildPositionIndicated="True"
                Orientation="Vertical"
                />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
    <ListBox.ItemContainerStyle>
        <Style 
            TargetType="ListBoxItem" 
            BasedOn="{StaticResource {x:Type ListBoxItem}}"
            >
            <Style.Triggers>
                <DataTrigger Value="True">
                    <DataTrigger.Binding>
                        <MultiBinding 
                            Converter="{StaticResource EqualsConverter}">
                            <Binding 
                                Path="DataContext.HighlightIndex" 
                                RelativeSource="{RelativeSource AncestorType=ListBox}" 
                                />
                            <Binding 
                                Path="(hbo:PanelBehaviors.ChildIndex)" 
                                RelativeSource="{RelativeSource Self}" 
                                />
                        </MultiBinding>
                    </DataTrigger.Binding>
                    <Setter Property="Background" Value="Red" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

转换器:

using System.Windows;
using System.Windows.Controls;

namespace HollowEarth.Behaviors
{
    public static class PanelBehaviors
    {
        public static void UpdateChildIndexProperties(Panel panel)
        {
            for (int i = 0; i < panel.Children.Count; ++i)
            {
                var child = panel.Children[i];
                SetChildIndex(child, i);
            }
        }

        #region PanelBehaviors.IsChildPositionIndicated Attached Property
        public static bool GetIsChildPositionIndicated(Panel panel)
        {
            return (bool)panel.GetValue(IsChildPositionIndicatedProperty);
        }
        public static void SetIsChildPositionIndicated(Panel panel, bool value)
        {
            panel.SetValue(IsChildPositionIndicatedProperty, value);
        }

        /// <summary>
        /// Behavior which causes the Panel to identify its first and last children with attached properties. 
        /// </summary>
        public static readonly DependencyProperty IsChildPositionIndicatedProperty =
            DependencyProperty.RegisterAttached("IsChildPositionIndicated", typeof(bool), typeof(PanelBehaviors),
                new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsArrange, IsChildPositionIndicated_PropertyChanged));
        private static void IsChildPositionIndicated_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Panel panel = (Panel)d;
            ((Panel)d).LayoutUpdated += (s, e2) => UpdateChildIndexProperties(panel);
        }
        #endregion PanelBehaviors.IsChildPositionIndicated Attached Property

        #region PanelBehaviors.ChildIndex Attached Property
        public static int GetChildIndex(UIElement obj)
        {
            return (int)obj.GetValue(ChildIndexProperty);
        }

        public static void SetChildIndex(UIElement obj, int value)
        {
            obj.SetValue(ChildIndexProperty, value);
        }

        public static readonly DependencyProperty ChildIndexProperty =
            DependencyProperty.RegisterAttached("ChildIndex", typeof(int), typeof(PanelBehaviors),
                new FrameworkPropertyMetadata(-1,
                    FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsParentArrange));
        #endregion PanelBehaviors.ChildIndex Attached Property
    }
}

viewmodel只是一个快捷方式:public class EqualsConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { return Object.Equals(values[0], values[1]); } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } ObservableCollection<String> Itemsint HighlightIndex { get; set; }

答案 1 :(得分:1)

第二个解决方案:

如果你有一个绑定到ListView itemsSource的Item数组,并且每个Item都实现了INotifyPropertyChanged,那么你可以这样做:

<ListView ItemsSource="{Binding MyItemsList}">
        <ListView.ItemTemplate>
            <ItemContainerTemplate>
                <Grid>
                    <Grid.Style>
                        <Style TargetType="Grid">
                            <Setter Property="Background" Value="Transparent"/>
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding ShouldChangeBackground}" Value="true">
                                    <Setter Property="Background" Value="Red"/>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </Grid.Style>

                </Grid>
            </ItemContainerTemplate>
        </ListView.ItemTemplate>
    </ListView>

ShouldChangeBackground是Item内的布尔值。当你希望它改变背景颜色时,你将这个布尔值设置为true,然后将它设置为False,它应该恢复正常。

另一种解决方案可能是使用转换器:

    class TrueToBackgroundConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is Boolean && (Boolean)value)
            return Brushes.Red;

        return Brushes.Transparent;
    }

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

并在您的代码中:

 <ListView ItemsSource="{Binding Element, FallbackValue=123123213213123213213}">
        <ListView.ItemTemplate>
            <ItemContainerTemplate>
                <Grid Background="{Binding ShouldChangeBackground, Converter={StaticResource TrueToBackgroundConverter}}">
                </Grid>
            </ItemContainerTemplate>
        </ListView.ItemTemplate>
    </ListView>