ViewModel和绑定动态可添加的组合框

时间:2010-07-28 08:25:56

标签: wpf binding viewmodel dynamic

我没有找到解决方案,但我认为它应该是可行的。

我在一个集合中有很多项目,想要选择其中的一些。每个项目都有一个CanInclude属性,包含可以选择的元素(如果已经选中)。

  • Item1 CanInclude:Item4,Item5
  • Item2 CanInclude:Item3,Item4
  • Item3 CanInclude:Item2
  • Item4 CanInclude:Item1
  • Item5 CanInclude:Item2,Item3

在其他地方选择了一个起始元素。

因此,如果开始项目是Item1,我想要一个包含Item4和Item5的组合框。如果我在这个组合框中选择Item5并单击一个'+'按钮我想在下面找到一个新的Box,其中包含Item2,Item3(从最后一个复选框)和Item4(从开始项目开始),依此类推,直到没有其他项目可以选择或用户点击“确定”。

我想到了viewmodel中的一个简单集合,其中[0]包含start元素,[1]是1. comboBox的选定元素,依此类推。但我不知道我应该如何动态添加组合框或让comboBox在所选项的集合中创建[n]元素。此外,我想不出一种方法可以在新复选框中包含已选择项目的CanInclude属性的所有项目。

如果有人有想法,我会非常感激。

修改 只是为了表达我想要像这样(包括伪代码,因为你不能做{Binding} + {Binding},但我认为你明白了):

<ComboBox ItemsSource="{Binding Path=SelectableItems}" SelectedItem="{Binding Path=SelectedItem1}" />
<ComboBox ItemsSource="{Binding Path=SelectedItem1.CanInclude}" SelectedItem="{Binding Path=SelectedItem2}"/>
<ComboBox ItemsSource="{Binding Path=SelectedItem1.CanInclude} + {Binding Path=SelectedItem2.CanInclude} - {Binding Path=SelectedItem1} - {Binding Path=SelectedItem2}" SelectedItem="{Binding Path=SelectedItem3}"/>

但我希望它适用于非固定数量的条目。

1 个答案:

答案 0 :(得分:1)

您可以模板化ListBox,以便每个项目都是一个组合框。这样,您可以将ListBox的数据源绑定到表示项目的ViewModel的ObservableCollection。类似的东西:

public class TopLevelViewModel
{
    private List<ItemViewModel> _allItems;

    public ObservableCollection<ItemViewModel> CurrentlySelectedItems { get; set; }

    public TopLevelViewModel()
    {
         DefineAllItems()
         SelectFirstItem()
    }

    private void DefineAllItems()
    {
        ItemViewModel item1 = new ItemViewModel { Name = "Item1" }
        item1.SelectedItemChanged += HandleItemViewModelSelectedItemChanged;

        ItemViewModel item2 = new ItemViewModel { Name = "Item2" }
        item2.SelectedItemChanged += HandleItemViewModelSelectedItemChanged;

        ItemViewModel item3 = new ItemViewModel { Name = "Item3" }
        item3.SelectedItemChanged += HandleItemViewModelSelectedItemChanged;

        item1.CanInclude = new ObservableCollection<ItemViewModel>
        {
              item2, item3
        }

        item2.CanInclude = new ObservableCollection<ItemViewModel>
        {
              item3
        }

        _allItems = new List<ItemViewModel>
        {
              item1, item2, item3
        }            
    }

    private void SelectFirstItem()
    {
         //Add item1 as the first combobox
         CurrentlySelectedItems.Add(_allItems[0]);
    }

    private void HandleItemViewModelSelectedItemChanged(object sender, EventArgs e)
    {
        ItemViewModel parent = (ItemViewModel)sender;

        //Find the view model whose item has changed in the CurrentlySelectedItems
        int indexOfParent = CurrentlySelectedItems.IndexOf(parent);

        //Remove all itemviewmodels below that item
        CurrentlySelectedItems.RemoveRange(
                   indexOfParent+1,
                   CurrentlySelectedItems.Count-(indexofParent+1))

        //Add the selected item into the list
        CurrentlySelectedItems.Add(parent.SelectedItem);            
    }
}

public class ItemViewModel
{
    public string Name { get; set; }
    public ObservableCollection<ItemViewModel> CanInclude { get; set; }
    public ItemViewModel SelectedItem { get; set; }

    public event EventHandler SelectedItemChanged;
}

然后将ListBox绑定到CurrentlySelectedItems,将模板内的ComboBox绑定到CanInclude:

<ListBox ItemsSource="{Binding CurrentlySelectedItems}">
   <ListBox.ItemTemplate>
       <DataTemplate>
          <ComboBox ItemsSource="{Binding CanInclude}"
                    DisplayMemberPath="{Binding Title}"
                    SelectedItem="{Binding SelectedItem}"/>
       </DataTemplate>
   </ListBox.ItemTemplate>
</ListBox>

编辑添加更适合问题的解决方案:

的Xaml:

<ListBox ItemsSource="{Binding PreviouslySelectedItems}"/>
<ComboBox ItemsSource="{Binding CanInclude}"
          DisplayMemberPath="{Binding Title}"
          SelectedItem="{Binding SelectedItem}"/>
<Button Content="Add"
        Command="{Binding AddCommand}"/>

视图模型:

public class TopLevelViewModel
{
      public ObservableCollection<ItemViewModel> PreviouslySelectedItems { get; private set; }
      public ObservableCollection<ItemViewModel> CanInclude { get; private set; }
      public ItemViewModel SelectedItem { get; set; }

      //Set up all the items as above, and pre-populate the first item
      //and the initial CanInclude options.

      //When the Add button is clicked
      public void ExecuteAdd()
      {
           //Add the currently selected item to the Listbox
           PreviouslySelectedItems.Add(SelectedItem)

           //Rebuild the CanInclude list
           CanInclude.Clear();

           var newCanInclude =
               PreviouslySelectedItems.SelectMany(x => x.CanInclude)
                                      .Where(x => !PreviouslySelectedItems.Contains(x))

           CanInclude.AddRange(newCanInclude);
      }
}
相关问题