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 中进行绑定。
我能想到的可能性:
我应该在 ViewModel 中引用视图吗?要找出 list2 的选定项目?
这可能是对 MVVM 模式的突破?正确吗?
(当在 DataContextChanged 上设置 DataContext 时,我可以将视图设置为 VM 的父视图。)
或者我能否以一种我拥有所有可用信息的方式绑定它,以自动以某种方式神奇地将名称添加到 list2item? (如何?)
我要不要试试多重绑定。我以前没有用过它,我觉得它对于这个 "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。
您想了解更多吗?
我正在开发一个用户控件,如果我想遵守 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 中进行绑定。
我能想到的可能性:
我应该在 ViewModel 中引用视图吗?要找出 list2 的选定项目?
这可能是对 MVVM 模式的突破?正确吗?
(当在 DataContextChanged 上设置 DataContext 时,我可以将视图设置为 VM 的父视图。)或者我能否以一种我拥有所有可用信息的方式绑定它,以自动以某种方式神奇地将名称添加到 list2item? (如何?)
我要不要试试多重绑定。我以前没有用过它,我觉得它对于这个 "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。