MVVM 数据绑定

6
我是一个有用的助手,可以翻译文本。
我有一个ComboBox,其DataContext在应用程序启动时定义为适当的ViewModel。 我想从XML文件中获取项目,但用户选择绑定到ViewModel,最终绑定到模型。
XAML:
<ComboBox x:Name="cbConnection"
          ItemsSource="{Binding Source={StaticResource XmlConnectionList}, XPath=//ComboItem}"
          DisplayMemberPath="Key"
          SelectedValuePath="Value"
          SelectionChanged="{Binding Path=DataContext.cbConnection_SelectionChanged}"
          />

但是在运行时我遇到了以下异常:
{"无法将类型为 'System.Reflection.RuntimeEventInfo' 的对象转换为类型 'System.Reflection.MethodInfo'。"}
我们知道 ViewModel 已经适当地设置为 View 窗口的 DataContext。我做错了什么?

嘿,Sammarcow... 你怎么样了?最终它起作用了吗? - PGallagher
2个回答

13

您正在使用;

SelectionChanged="{Binding Path=DataContext.cbConnection_SelectionChanged}" 

实际上是一个事件。

您应该将公共属性(可能实现了INotifyPropertyChanged)绑定到ViewModel中的SelectedItem属性,以管理选择更改。

假设您的窗口具有DataContext,而不是ComboBox本身...

SelectedItem 绑定版本:

因此,您的XAML应该类似于:

<ComboBox x:Name="cbConnection"
          ItemsSource="{Binding Source={StaticResource XmlConnectionList}, XPath=//ComboItem}"
          DisplayMemberPath="Key"
          SelectedValuePath="Value"
          SelectedItem="{Binding Path=DataContext.cbConnectionSelectedItem}"
/>

并且在你的 ViewModel 中;

Private _cbConnectionSelectedItem As XmlElement

Public Property cbConnectionSelectedItem As XmlElement
     Get
         Return _cbConnectionSelectedItem
     End Get
     Set(value As XmlElement)
         If value.Equals(_cbConnectionSelectedItem) = False Then
             _cbConnectionSelectedItem = value
             OnPropertyChanged("cbConnectionSelectedItem")
            End If
     End Set
End Property

文本绑定版本:

当然,如果您只对所选择的文本值感兴趣,理论上您可以将 ComboBox 的 Text 属性绑定到 ViewModel 中的公共字符串属性;

您的 XAML 代码如下:

<ComboBox x:Name="cbConnection"
              ItemsSource="{Binding Source={StaticResource XmlConnectionList}, XPath=//ComboItem}"
              DisplayMemberPath="Key"
              SelectedValuePath="Value"
              Text="{Binding Path=DataContext.cbConnectionText}"
    />

还有你的ViewModel;

Private _cbConnectionText As String

Public Property cbConnectionText As String
     Get
         Return _cbConnectionText
     End Get
     Set(value As String)
         If value.Equals(_cbConnectionText) = False Then
             _cbConnectionText = value
             OnPropertyChanged("cbConnectionText")
            End If
     End Set
End Property

SelectedValue绑定版本:

如果您正在显示Key,但希望从Key/Value Pair中获取Value,则应绑定到SelectedValue;

XAML;

<ComboBox x:Name="cbConnection" 
    ItemsSource="{Binding Source={StaticResource XmlConnectionList}, XPath=//ComboItem}"
    DisplayMemberPath="@Key" 
    SelectedValuePath="@Value" 
    SelectedValue="{Binding Path=DataContext.cbConnectionValue}" />

视图模型;

Private _cbConnectionValue As String

Public Property cbConnectionValue As String
     Get
         Return _cbConnectionValue
     End Get
     Set(value As String)
         If value.Equals(_cbConnectionText) = False Then
             _cbConnectionValue = value
             OnPropertyChanged("cbConnectionValue")
            End If
     End Set
End Property

请注意多出来的 @ 符号。

如我上面提到的,这里假设你的窗口已经设置了 DataContext。如果没有设置,则从上面的绑定中删除 "DataContext"!

我假设你当前在 ComboBox 中看到了列出的项目?

希望这有所帮助!


嗯,我不确定自己做错了什么,但是`<ComboBox x:Name="cbConnection" ItemsSource="{Binding Source={StaticResource XmlConnectionList}, XPath=//ComboItem}" DisplayMemberPath="Key" SelectedValuePath="Value" SelectedItem="{Binding Path=DataContext.ConnectionString}" />`似乎不能触发ViewModel中ConnectionString的getter或setter属性。 - sammarcow
1
我可能错了,但是这个绑定难道不是解析为DataContext.DataContext.ConnectionString的属性路径吗?尝试使用SelectedItem="{Binding Path=ConnectionString}"。 - Wes Cumberland
啊...是的,Wes,你发现得很好。如果你正在设置ComboBox的DataContext,而不是窗口的话,那么请从上面的绑定中删除"DataContext."! - PGallagher
太棒了!并不傻,通常有很多方法可以实现相同的结果...看起来SelectedValue是适合你的! - PGallagher
3
这段话需要翻译为:虽然和问题不直接相关,但你的评论“实际上是一个事件”促使我检查了一下我的XAML代码,在那里我试图将布尔值绑定到CheckBox的“Checked”属性上。结果发现,“Checked”其实是一个事件!将它绑定到“IsChecked”而不是“Checked”,一切都正常了。 - Jon
显示剩余4条评论

7
你需要使用事件触发器来处理comboBox选择更改事件,你可以尝试以下代码:

<ComboBox Margin="192,5,5,5" DisplayMemberPath="AttachmentName" ItemsSource="{Binding AttachementList, Mode=TwoWay}" Style="{StaticResource BasicComboBoxStyle}" BorderThickness="2" BorderBrush="DarkGray"
                          Name="cmb_AttchDetails" Width="287" Height="25" SelectedItem="{Binding Defaultrequiredattachment, Mode=TwoWay}">
                    <l:Interaction.Triggers>
                        <l:EventTrigger EventName="SelectionChanged">
                            <l:InvokeCommandAction Command="{Binding DataContext.AttachmentNameCommand,Mode=TwoWay,RelativeSource={RelativeSource AncestorType=controls:ChildWindow}}" CommandParameter="{Binding ElementName=cmb_AttchDetails,Path=SelectedItem}" />
                        </l:EventTrigger>
                    </l:Interaction.Triggers>
                </ComboBox>

对于这些内容,您需要添加引用,例如

  xmlns:l="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 

我没有测试过这个,但是被接受的答案似乎确实能够有效地达到相同的结果。 - sammarcow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接