将ListBox特定项目背景绑定到特定值

时间:2010-10-11 17:08:40

标签: c# wpf data-binding

我是WPF的新手,仍在使用绑定等等,所以这可能是一个基本问题。

考虑以下课程:

class DataHolder
{
    public List<int> Data;

    // Points to one of the items in Data. Thus can be between 0 and Data.Count
    public int Pointer;
}

我已将ListBox的DataContext设置为上面类的实例,其ItemSource是实例的“数据”。

现在我想在ListBox中标记包含数据[指针] 的列表项的颜色为灰色。

我应该使用什么?我已尝试使用DataTriggers,但我不确定如何使用它们比较两个不同的值。我不想在此时使用IValueConverter,除非不可能这样做。

编辑:随意将公开数据转换为上述类中的属性

谢谢!

3 个答案:

答案 0 :(得分:2)

我之前通过创建我称之为DataViewModel的方式完成了这样的事情。这基本上是集合中每个项目的ViewModel。我用你的例子快速尝试了它并且它有效。我会在下面粘贴我的所有代码,如果你愿意,应该能够将其拉入并执行它。

<强> MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1"
    Title="MainWindow" Height="350" Width="525">

<Window.DataContext>
    <local:MainWindow_ViewModel/>
</Window.DataContext>
<StackPanel>
    <TextBox Text="{Binding Pointer, Mode=TwoWay}" Height="20" Width="100"/>
    <ListBox ItemsSource="{Binding MyDataHolder}" Height="20" Width="100">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Value}" Background="{Binding Color}"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</StackPanel>

<强> MainWindow_ViewModel.cs

public class MainWindow_ViewModel
{
    public MainWindow_ViewModel() 
    {
        data = new DataHolder();

        foreach (int value in data.Data)
        {
            myData.Add(new Data_DataViewModel() { Value = value });
        }

        this.Pointer = 4;
    }

    private DataHolder data;
    private List<Data_DataViewModel> myData = new List<Data_DataViewModel>();

    public List<Data_DataViewModel> MyDataHolder
    {
        get
        {
            return myData;
        }
    }

    public int Pointer
    {
        get { return this.data.Pointer; }
        set 
        {
            this.data.Pointer = value;
            foreach (Data_DataViewModel dvm in this.myData)
            {
                dvm.UpdateColor(this.data.Pointer);
            }
        }
    }
}

<强> DataHolder.cs

public class DataHolder
{
    public List<int> Data
    {
        get { return data; }   
    }
    private List<int> data = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8 };

    public int Pointer = 3;
}

<强> Data_DataViewModel.cs

public class Data_DataViewModel : INotifyPropertyChanged
{
    public int Value
    {
        get { return val; }
        set { val = value; } 
    }
    private int val;

    public Brush Color
    {
        get 
        {
            if (this.Value == pointer)
            {
                return Brushes.Gray;
            }
            else
            {
                return Brushes.Pink;
            }
        }
    }

    private int pointer;

    public void UpdateColor(int pointerValue)
    {
        this.pointer = pointerValue;
        OnPropertyChanged("Color");
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

答案 1 :(得分:1)

有趣的问题。我的解决方案使用ItemTemplateSelector。在其SelectTemplate覆盖中,您可以访问ListItems所在的Panel(VirtualizingStackPanel)。这里的技巧是,当每个ListItem被添加到ListBox时,会调用此覆盖,我们可以使用ChildCount在ListBox中确定其索引。这有助于我们进行比较并选择正确的模板。

<强> Main.xaml

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApplication1" mc:Ignorable="d" x:Class="WpfApplication1.MainWindow"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>       
        <DataTemplate
            x:Key="DataTemplateWithHighlight">
            <StackPanel>
                <TextBlock HorizontalAlignment="Stretch"
                    Text="{Binding Mode=OneWay}"
                    Background="Gray" />
            </StackPanel>
        </DataTemplate>
        <DataTemplate
            x:Key="DataTemplateWithoutHighlight">
            <StackPanel>
                <TextBlock
                    HorizontalAlignment="Stretch"
                    Text="{Binding Mode=OneWay}"
                    Background="White" />
            </StackPanel>
        </DataTemplate>
        <local:ListBoxItemTemplateSelector
            x:Key="listBoxItemTemplateSelector"
            HighlightedItemTemplate="{StaticResource DataTemplateWithHighlight}"
            NonHighlightedItemTemplate="{StaticResource DataTemplateWithoutHighlight}" />

    </Window.Resources>
    <StackPanel Orientation="Vertical" d:LayoutOverrides="Height" HorizontalAlignment="Center" VerticalAlignment="Center">
        <ListBox
            x:Name="listBoxWithMeaninglessNumbers"
            Height="100"
            Width="100"
            ItemsSource="{Binding Data}"
            ItemTemplateSelector="{DynamicResource listBoxItemTemplateSelector}">          
        </ListBox>
    </StackPanel>
</Window>

DataItems类

 public  class DataItems
    {
      public List<int> Data { get; set;}
      public int HighlightedIndex { get; set; }
    }

一些初步数据让你前进

public static class DataStub
{
        public static DataItems TestDataItems
        {
            get
            {
                var dataItems = new DataItems();
                dataItems.Data = new List<int>(){1,5,9,6,8};
                dataItems.HighlightedIndex = 2;

                return dataItems;
            }
        }
}

<强> MainWindow.Xaml.cs

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        listBoxWithMeaninglessNumbers.DataContext = DataStub.TestDataItems;
    }
}

TemplateSelector类:

 public class ListBoxItemTemplateSelector:DataTemplateSelector
    {
       public DataTemplate NonHighlightedItemTemplate { get; set; }
       public DataTemplate HighlightedItemTemplate { get; set; }



         public override DataTemplate SelectTemplate(object item, DependencyObject container)
       {
             var listBoxItem = ((FrameworkElement) container).TemplatedParent as ListBoxItem;
             var panel = VisualTreeHelper.GetParent(listBoxItem) as Panel;
             var highlightedIndex = (panel.DataContext as DataItems).HighlightedIndex;
             var currentChildIndex = panel.Children.Count-1;

             return (highlightedIndex == currentChildIndex) ? HighlightedItemTemplate : NonHighlightedItemTemplate;
            }
    }
}

希望这有帮助。

答案 2 :(得分:1)

列表框还有一个可以绑定的SelectedIndex属性。使索引成为ViewModel上的属性(提示:数据属性,同时确保该属性触发notify change event)。然后编辑列表框项的Selected State

IMO比其他提案容易得多,并且适当地使用了模板和绑定 more