将包含索引的ObservableCollection <int>绑定到CheckBoxes的ListBox </int>

时间:2013-12-23 12:08:54

标签: c# wpf xaml data-binding

在我的C#/ WPF / .NET 4.5项目中,我有一个ObservableCollection<int>来保存索引。我还有一个ListBox,其ItemsPanelTemplate设置为UniformGrid(包含20行和20列),其ItemTemplate设置为CheckBox es。< / p>

我希望ObservableCollection<int>保存已检查的CheckBoxes的索引。这应该通过TwoWay绑定来完成:当int添加ObservableCollection时,CheckBoxes UniformGrid中的CheckBox应该被选中或取消选中;当我选中或取消选中ObservableCollection时,应将其索引添加到<ListBox x:Name="myListBox" SelectionMode="Multiple" ItemsSource="{Binding Cells, Converter={StaticResource cellsConverter}}"> <ListBox.ItemsPanel> <ItemsPanelTemplate> <UniformGrid Rows="20" Columns="20"></UniformGrid> </ItemsPanelTemplate> </ListBox.ItemsPanel> <ListBox.ItemTemplate> <DataTemplate> <CheckBox IsChecked="{Binding}"/> </DataTemplate> </ListBox.ItemTemplate> </ListBox> 或从ObservableCollection<int>中删除。

我尝试使用转换器以下列方式完成此操作:

XAML:

public class Frame : INotifyPropertyChanged {
    private ObservableCollection<int> _cells;

    public ObservableCollection<int> Cells {
      get { return _cells; }
      set {
        _cells = value;
        OnPropertyChanged("Cells");
      }
    }

    public Frame() {
      Cells = new ObservableCollection<int>();
    }

    // Event handler for INotifyPropertyChanged 
    public event PropertyChangedEventHandler PropertyChanged;
    void OnPropertyChanged(string propName) {
      if (PropertyChanged != null) {
        PropertyChanged(this, new PropertyChangedEventArgs(propName));
      }
    }
  }

包含[ValueConversion(typeof(ObservableCollection<int>), typeof(ObservableCollection<bool>))] public class CellsConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { ObservableCollection<int> ints = (ObservableCollection<int>)value; ObservableCollection<bool> bools = new ObservableCollection<bool> (); for (int i = 0; i < 400; i++) { bool b = new bool(); if (ints.Contains(i)) b = true; else b = false; bools.Add(b); } return bools; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { ObservableCollection<bool> bools = (ObservableCollection<bool>)value; ObservableCollection<int> ints = new ObservableCollection<int>(); foreach (bool b in bools) { if (b == true) ints.Add(bools.IndexOf(b)); } return ints; } } 的类

XamlParseException

转换器:

ListBox

这可能不是实现此目的的理想方法,在这种情况下,如果有人提出不同的方法,我将不胜感激。

当我运行它时,我得到一个ParentOfMyListBox.DataContext = new Frame(); 说“双向绑定需要Path或XPath”。我想问题类似于the one posted here,但我无法弄清楚如何将解决方案应用到我使用转换器的情况。

问题:

  • 这是将索引集合绑定到indexes.Add(0); indexes.Add(3); 的好方法吗?
  • 如果是,我该如何纠正我的实施?
  • 如果没有,会有什么更好的方式?

修改

为清楚起见,说明了我想要实现的目标:

indexes.Remove(0);

myListBox的外观:

indexes

3

然后,如果我手动检查其中一个单元格......

现在8包含{{1}}和{{1}}。

1 个答案:

答案 0 :(得分:3)

记住,亲吻 - 保持简单,愚蠢。

1)创建一个包装类,其中包含:

  • IsChecked布尔属性
  • 值整数属性

在XAML中,绑定IsChecked属性:

<ListBox
    SelectionMode="Multiple"
    ItemsSource="{Binding Cells}">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <UniformGrid Rows="20" Columns="20"></UniformGrid>
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <CheckBox IsChecked="{Binding IsChecked}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

现在,如果你需要获得ObservableCollection;你可以使用简单的LINQ查询:

new ObservableCollection<int>(Cells.Where(x= x.IsChecked).Select(x => x.Value));

转换器破解不应该使用,但可以给你实现它的想法没有一个:

private void UpdateUnderlyingCollection(
    ObservableCollection<int> underlyingCollection , 
    int element, 
    bool isChecked)
{
    if (!isChecked)
        underlyingCollection.Remove(element);
    else if(!underlyingCollection.Contains(element))
        underlyingCollection.Add(element);
}

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    // todo; weak references
    var underlyingCollection = (ObservableCollection<int>)value;
    var lookup = underlyingCollection.ToLookup(x => x);

    var presentableCollection = new ObservableCollection<Wrap>();
    foreach (var i in Enumerable.Range(0, 400))
    {
        var damnLambdaYuNoCaptureByValue = i;
        var wrap = new Wrap { IsChecked = lookup.Contains(i)};
        wrap.PropertyChanged += (sender, args) =>
            {
                if(args.PropertyName == "IsChecked")
                    UpdateUnderlyingCollection(
                       underlyingCollection, 
                       damnLambdaYuNoCaptureByValue, 
                       wrap.IsChecked);
            };

        presentableCollection.Add(wrap);
    }

    return presentableCollection;
}