根据另一个集合设置ListBox SelectedItems

时间:2013-03-18 09:56:57

标签: c# wpf mvvm .net-4.0

我有一个ListBox绑定到MyCollection类型的IEnumerable<string>

 <ListBox x:Name="ListBox" ItemsSource="{Binding MyCollection, Mode=OneWay}" SelectionMode="Multiple"/>

我有另一个List<string> SubCollection,其中包含MyCollection

的子集

每当SubCollection发生变化时,我都希望根据SelectedItems

突出显示SubCollection

是否有BindingBehaviour或其他任何方式来实现此目标?

修改

假设我ListBox绑定MyCollection { "Orange", "Mango", "Stawberry", "Pineapple" }

假设我按下按钮从数据库加载数据,结果为“橙色”,“芒果”,然后放入SubCollectionListBox现在应该将“橙色”,“芒果”作为其SelectedItems

6 个答案:

答案 0 :(得分:5)

我有一个建议。

您可以绑定到&#34; IsSelected&#34; ListBoxItem的属性。

要做到这一点,你必须使用collection of objects(让我们说MyListBoxItem)而不是字符串集合。

public class  MyListBoxItem
{
    public string Description { get; set; }
    public bool IsSelected { get; set; }
}

使用此&#34; IsSelected&#34; MyListBoxItem类的属性绑定&#34; IsSelected&#34; ListBoxItem的财产。

例如:在您查看模型时,

this.MyCollection = new ObservableCollection<MyListBoxItem>();

MyListBoxItem item1 = new MyListBoxItem()
item1.Description = "Mango";
item1.IsSelected = true;
MyCollection .add(item1);

MyListBoxItem item2 = new MyListBoxItem()
item2 .Description = "Orange";
item2 .IsSelected = false;
MyCollection .add(item2 );

XAML(在ListBox内)

<ListBox.ItemContainerStyle>
    <Style TargetType="{x:Type ListBoxItem}">
        <Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}"/>
    </Style>
</ListBox.ItemContainerStyle>

答案 1 :(得分:4)

您可以为List创建AttachedProperty ListBox,以便在更改列表时将项目添加到ListBox.SelectedItems

AttachedProperty解决方案让WPF保持清洁,并保持MVVM模式。此外,它还可以在您的所有项目中重复使用此功能:)

以下是一个例子:

AttachedProperty:

public static class ListBoxExtensions
{
    // Using a DependencyProperty as the backing store for SearchValue.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SelectedItemListProperty =
        DependencyProperty.RegisterAttached("SelectedItemList", typeof(IList), typeof(ListBoxExtensions),
            new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnSelectedItemListChanged)));

    public static IList GetSelectedItemList(DependencyObject obj)
    {
        return (IList)obj.GetValue(SelectedItemListProperty);
    }

    public static void SetSelectedItemList(DependencyObject obj, IList value)
    {
        obj.SetValue(SelectedItemListProperty, value);
    }

    private static void OnSelectedItemListChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var listbox = d as ListBox;
        if (listbox != null)
        {
            listbox.SelectedItems.Clear();
            var selectedItems = e.NewValue as IList;
            if (selectedItems != null)
            {
                foreach (var item in selectedItems)
                {
                    listbox.SelectedItems.Add(item);
                }
            }
        }
    }
}

Xaml用法:

<ListBox ItemsSource="{Binding Items}" SelectionMode="Multiple"
         local:ListBoxExtensions.SelectedItemList="{Binding SelectedItems}" />


演示:

如果你想测试的工作示例:

的Xaml:

<Window x:Class="WpfApplication17.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication17"
        Title="MainWindow" Height="227" Width="170" Name="UI">
    <Grid DataContext="{Binding ElementName=UI}">
        <ListBox ItemsSource="{Binding Items}" SelectionMode="Multiple"
                 local:ListBoxExtensions.SelectedItemList="{Binding SelectedItems}"  Margin="0,0,0,37"   >
                 <ListBox.Resources>
                    <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="{x:Static SystemColors.HighlightColor}" />
                    <Style TargetType="ListBoxItem">
                       <Style.Triggers>
                          <Trigger Property="IsSelected" Value="True">
                             <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
                          </Trigger>
                       </Style.Triggers>
                    </Style>
                 </ListBox.Resources>
        </ListBox>
        <Button Content="Populate SelectedItemList" Click="Button_Click" Height="32" Margin="2,0,1,2" VerticalAlignment="Bottom"/>
    </Grid>
</Window>

代码:

namespace WpfApplication17
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        private List<string> _selectedItems = new List<string>();
        private ObservableCollection<string> _items = new ObservableCollection<string> 
        { "Orange", "Mango", "Stawberry", "Pineapple", "Apple", "Grape", "Banana" };

        public MainWindow()
        {
            InitializeComponent();
        }

        public ObservableCollection<string> Items
        {
            get { return _items; }
            set { _items = value; }
        }

        public List<string> SelectedItems
        {
            get { return _selectedItems; }
            set { _selectedItems = value; OnPropertyChanged("SelectedItems"); }
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            SelectedItems = new List<string> { "Orange", "Pineapple", "Apple" };
        }

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

    public static class ListBoxExtensions
    {
        // Using a DependencyProperty as the backing store for SearchValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SelectedItemListProperty =
            DependencyProperty.RegisterAttached("SelectedItemList", typeof(IList), typeof(ListBoxExtensions),
                new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnSelectedItemListChanged)));

        public static IList GetSelectedItemList(DependencyObject obj)
        {
            return (IList)obj.GetValue(SelectedItemListProperty);
        }

        public static void SetSelectedItemList(DependencyObject obj, IList value)
        {
            obj.SetValue(SelectedItemListProperty, value);
        }

        private static void OnSelectedItemListChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var listbox = d as ListBox;
            if (listbox != null)
            {
                listbox.SelectedItems.Clear();
                var selectedItems = e.NewValue as IList;
                if (selectedItems != null)
                {
                    foreach (var item in selectedItems)
                    {
                        listbox.SelectedItems.Add(item);
                    }
                }
            }
        }
    }
}

结果:

enter image description here

答案 2 :(得分:2)

标准数据绑定不起作用,因为SelectedItems属性是只读的。

一种简单的方法是根据SubCollection中的项目手动迭代MyCollection并设置每个项目的IsSelected属性。 为此,MyCollection列表中的项应包含从ListBoxItem继承的对象,该对象将公开IsSelected属性。

以下是一个示例WPF应用程序:

按钮单击将根据SubCollection列表中的项目更新所选项目。现在我已经硬编码了SubCollection列表的值。

根据您的实现,您可以更新您的SubCollection,并将按钮单击事件中的代码适当地挂钩到任何其他事件。(比如将SubCollection列表作为ObservableCollection并挂钩到ObservableCollection.CollectionChange)

<强> 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" 
        Title="MainWindow" Height="250" Width="255">
    <Grid>
        <StackPanel Orientation="Vertical">
            <ListBox x:Name="ListBox" ItemsSource="{Binding MyCollection}" SelectionMode="Extended" Margin="10,10"/>
            <Button Content="UpdateSelection"  Click="Button_Click" Margin="10,10"/>
        </StackPanel>
    </Grid>
</Window>

<强> MainWindow.xaml.cs

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            _myCollection = new ObservableCollection<MyListBoxItem>() { new MyListBoxItem("Orange"), new MyListBoxItem("Mango"), new MyListBoxItem("Stawberry"), new MyListBoxItem("Pineapple") };

            //Items to be selected on this.MyCollection ListBox
            this.SubCollection = new List<string>() { "Pineapple", "Mango" };

            this.DataContext = this;
        }

        private ObservableCollection<MyListBoxItem> _myCollection;
        public ObservableCollection<MyListBoxItem> MyCollection
        {
            get { return _myCollection; }
            set
            {
                this._myCollection = value;
            }
        }

        public IList<string> SubCollection { get; set; }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            // Clear all the selected items in the ListBox
            this.MyCollection.ToList().ForEach(item => item.IsSelected = false);

            // SELECT only the items in MySubCollection into this.MyCollection ListBox
            this.MyCollection.Where(item => this.SubCollection.Contains(item.Content.ToString())).ToList().ForEach(item => item.IsSelected= true);
        }
    }

    public class MyListBoxItem : ListBoxItem
    {
        public MyListBoxItem(string displayName)
        {
            this.Content = displayName;
        }
    }
}

答案 3 :(得分:1)

查看此博文:how-to-databind-to-selecteditems。有一个附带代码的演示项目。

答案 4 :(得分:1)

使用&#34; SelectedValue&#34; ListBox的属性。 (因为您正在使用字符串集合来绑定列表框。)

  1. 在视图模型中定义字符串类型属性(让我们说MySelectedValue)。
  2. 然后将其绑定到&#34; SelectedValue&#34;两个列表框的属性。 (记住在主列表框中设置Mode = TwoWay
  3. 假设您在子集合列表框中选择项目时将执行一个方法。 (您必须触发Sub Collection ListBox的SelectionChanged事件)
  4. 那就是它。
  5.   

    因此。你要做的是:

         

    使用相同的属性绑定&#34; SelectedValue&#34;两种财产   列表框。

    如果您想将一组对象绑定到列表框,请说。 然后使用SelectedItem属性来完成此任务。

答案 5 :(得分:0)

如果您知道要选择的索引号,可以使用

int[] index = {1, 2, 5};
for( int i in index) 
{    
   listBox.SetSelected( i, true );
}