WPF 命令如何获取所有必要的信息以添加到正确的列表项

WPF command how to get all necessary info to add to the correct list item

我正在开发一个用户控件,如果我想遵守 MVVM 模型,我想知道如何正确地实现它。

我将我的真实用例简化为一个例子: 有一个名为 config.xaml 的配置视图和一个我称之为 ConfigVM 的视图模型。对于这个例子,我认为模型是不相关的,但如果你需要它作为你的答案,我会称之为 ConfigData。

在此视图中,有一个包含字符串值的组合框。组合框选中的值应该被添加到列表框的选中项中。要执行此操作,在组合框旁边有一个按钮 "Add name"。与命令绑定。
但是:列表框的选中项由主列表框的选中项定义。所以这有点级联。
我希望这张照片能为设置带来一些启发。

mvvm class 是这样编码的(缩写为明白意思):

class ConfigVM
{
    public ObservableList list1{}
}

class List1ItemVm
{
    public ObservableList List2{}
}

class List2Item
{
    public string Name{}
}

当前按钮的绑定是(当然不起作用):

      Command="{Binding AddCommand}"
      CommandParameter="{Binding SelectedItem, ElementName=comboBox}"

我的问题是:如何获取接收列表2中的选中项来添加组合框选中项?
从命令中,我获得了组合框所选项目的名称作为参数,但在命令内部的那一点上,我不知道应该将其添加到哪个列表中。

Ann.:我添加了级联列表,因为这是我的场景,使我更难获得正确的项目并在 xaml 中进行绑定。

我能想到的可能性:

  1. 我应该在 ViewModel 中引用视图吗?要找出 list2 的选定项目?
    这可能是对 MVVM 模式的突破?正确吗?
    (当在 DataContextChanged 上设置 DataContext 时,我可以将视图设置为 VM 的父视图。)

  2. 或者我能否以一种我拥有所有可用信息的方式绑定它,以自动以某种方式神奇地将名称添加到 list2item? (如何?)

  3. 我要不要试试多重绑定。我以前没有用过它,我觉得它对于这个 "easy" 问题来说有点过于复杂了。 (写转换器等)

更新 来自真实代码的更多信息: 组合框:

<StackPanel Grid.Row="0"
            Orientation="Horizontal"
            Grid.Column="1">
  <ComboBox x:Name="comboSymbols"
            HorizontalAlignment="Left"
            MinWidth="150"
            Margin="10,10,0,0"
            ItemsSource="{Binding SymbolsAvailable}"
            dd:DragDrop.IsDragSource="True"
            Height="22"
            VerticalAlignment="Top">
    <ComboBox.ItemTemplate>
      <DataTemplate>
        <StackPanel Orientation="Horizontal">
          <TextBlock Text="{Binding Name}" />
          <TextBlock Text=" | " />
          <TextBlock Text="{Binding Unit}" />
        </StackPanel>
      </DataTemplate>
    </ComboBox.ItemTemplate>
  </ComboBox>
  <Button Content="Symbol hinzufügen"
          HorizontalAlignment="Left"
          MinWidth="75"
          Margin="10,10,0,0"
          Command="{Binding AddCommand}"
          CommandParameter="{Binding SelectedItem, ElementName=comboSymbols}"
          Height="22"
          VerticalAlignment="Top" />
</StackPanel>

列表 2:

<ListBox x:Name="symbolsListBox"
         Grid.Column="1"
         HorizontalAlignment="Left"
         Height="175"
         Margin="26,39,0,0"
         Grid.Row="1"
         VerticalAlignment="Top"
         Width="137"
         DataContext="{Binding Path=SelectedItem, ElementName=channelListBox}"
         ItemsSource="{Binding Symbols}">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding Name}" />
        <TextBlock Text=" | " />
        <TextBlock Text="{Binding Unit}" />
      </StackPanel>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

列表 1:

        <ListBox x:Name="channelListBox" HorizontalAlignment="Left"
           Width="170"
           Margin="10,10,0,10"
           ItemsSource="{Binding ChannelCollection}"
           dd:DragDrop.IsDragSource="True"
           dd:DragDrop.IsDropTarget="True"
           dd:DragDrop.DropHandler="{Binding}"
           Height="504">
    <ListBox.ItemTemplate>
      <DataTemplate>
        <StackPanel Orientation="Horizontal">
          <TextBlock Text="{Binding Gid}" />
          <TextBlock Text=" | " />
          <TextBlock Text="{Binding Name}" />
        </StackPanel>
      </DataTemplate>
    </ListBox.ItemTemplate>
  </ListBox>

注意:此答案是与 OP 在问题下的对话的集合。


Should I reference the view inside the ViewModel? To find out the selected Item of list2? This is probably a break to the MVVM Pattern? correct? (I could set the view as a parent of the VM when the DataContext is set on DataContextChanged.)

在纯 MVVM 中,视图模型 (VM) 应与视图 (V) 分离,因此不应包含对底层 V 的 class 对象的引用。所以没有。

Or can I bind it in a way where I have all the information available to automatically somehow magic add the Name to the list2item? (how?)

是的。您可以将 V 数据绑定到 VM 中的 SelectedSomething,反之亦然。

WPF 绑定可以是单向的;双向 仅举两个例子。这意味着 listbox 中的选定项可以绑定到 VM,并且 VM 也可以设置选定项。当您考虑 VM 负责填充 listbox 时,剩下的就很容易了。

所以看起来你的 XAML 中的许多元素都在相互引用,特别是 SelectedItem 和你的 AddCommand 使用一个参数,所以遗憾的是,VM 并没有在所有情况下直接看到它。

"You mean I can add a property SelectedItem to the VM and bind it"

是的,没错,是的,这仍然是 MVVM。 XAML 元素相互引用也没有错(这就是力量),但在这种情况下,我可能会有一个 VM 属性 用于 SelectedItem。

您想了解更多吗?