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

发布于 2024-09-11 22:22:07 字数 1217 浏览 1 评论 0原文

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

我的收藏中有许多项目,想要选择其中的一些。每个项目都有一个 CanIninclude 属性,其中包含可以选择的元素(如果其本身已被选择)。

  • Item1 可以包括:Item4、Item5
  • Item2 可以包括:Item3、Item4
  • Item3 可以包括:Item2
  • Item4 可以包括:Item1
  • Item5 可以包括:Item2、Item3

在其他位置选择了起始元素。

因此,如果起始项是 Item1,我想要一个包含 Item4 和 Item5 的组合框。如果我在此组合框中选择 Item5 并单击“+”按钮,我想在下面获得一个新框,其中包含 Item2、Item3(来自最后一个复选框)和 Item4(来自起始项目)等,直到没有其他项目可以被选择或用户单击“确定”。

我想到了视图模型中的一个简单集合,其中 [0] 保存开始元素,[1] 1.comboBox 的选定元素等等。但我不知道应该如何动态添加组合框或让组合框在所选项目的集合中创建 [n] 元素。另外,我想不出一种方法来将已选定项目的 CanIninclude 属性的所有项目包含在新复选框中。

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

编辑: 只是为了说明,我想要这样的东西(包括伪代码,因为你不能执行 {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}"/>

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

I didn't find a solution for this but I think it should be doable.

I have a number of items in a collection and want to select some of them. Each item has a CanInclude property containing the elements that can be selected if itself is already selected.

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

A starting element is selected somewhere else.

So if start item is Item1, I want to have a comboBox with Item4 and Item5 in it. If i select Item5 in this comboBox and click on a '+' button I want to get a new Box underneath with Item2, Item3(from last checkbox) and Item4(from start item) and so on till there is no other item that can be selected or the user clicks 'OK'.

I have thought of a simple collection in the viewmodel, where [0] holds the start element, [1] the selected element of 1. comboBox and so on. But i don't know how i should dynamically add the comboBoxes or let a comboBox create the [n] element in the collection of selected items. Also I can't think of a way to include all items of the CanInclude properties of the already selected items in the new checkbox.

I would be very thankfull if anyone had an idea.

EDIT:
Just for explenation i want somehting like this (Pseudo code included since you can not do {Binding} + {Binding}, but i think you get the idea):

<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}"/>

But I want it to work for a non fixed number of entries.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

森林很绿却致人迷途 2024-09-18 22:22:07

您可以模板化列表框,以便每个项目都是一个组合框。这样您就可以将 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 绑定到 CurrentSelectedItems,并将模板内的 ComboBox 绑定到 CanIninclude:

<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}"/>

ViewModel:

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);
      }
}

You could template a ListBox so that each item is a combobox. That way you can bind the datasource of the ListBox to an ObservableCollection of ViewModels that represent the items. Something like:

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;
}

Then bind the ListBox to the CurrentlySelectedItems, and the ComboBox inside the template to the CanInclude:

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

Edited to add a solution that better fits the problem:

Xaml:

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

ViewModel:

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);
      }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文