WPF MVVM 将 ComboBox 绑定到 Datagrid 所选项目
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14144277/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF MVVM Binding ComboBox to Datagrid Selected Item
提问by RG21
Does anyone have an example of binding a ComboBox to a Selected Item of a DataGrid? I have tried a bunch of ways, but I can't seem to get it to work. I am fairly new to MVVM so I am doing something wrong. Any help would be appreciated. I have the datacontext of the grid that the combobox is in set to the datagrid, but when I select a row from the datagrid the combobox does not change. All of the text boxes are populated with the data from the datagrid, but the combobox does not change. The combobox in question is cmbRoles.
有没有人有将 ComboBox 绑定到 DataGrid 的选定项的示例?我已经尝试了很多方法,但我似乎无法让它发挥作用。我对 MVVM 还很陌生,所以我做错了。任何帮助,将不胜感激。我将组合框所在的网格的数据上下文设置为数据网格,但是当我从数据网格中选择一行时,组合框不会改变。所有文本框都填充了来自数据网格的数据,但组合框不会更改。有问题的组合框是 cmbRoles。
Thank you,
谢谢,
RG
RG
Here is the XAML:
这是 XAML:
<UserControl x:Class="Compliance.Views.UserAdministrationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Compliance"
xmlns:views="clr-namespace:Compliance.Views"
xmlns:helpers="clr-namespace:Compliance.Helpers"
xmlns:vm="clr-namespace:Compliance.ViewModels"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
mc:Ignorable="d"
d:DesignHeight="1000" d:DesignWidth="800">
<UserControl.Resources>
<helpers:ActiveStatusConverter x:Key="ActiveStatusConverter"/>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Row="0" Margin="15">
<Label Content="User" Height="25" FontSize="14" HorizontalContentAlignment="Center" />
<Grid HorizontalAlignment="Center" VerticalAlignment="Top" DataContext="{Binding ElementName=usersDG, Path=SelectedItem}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" MinHeight="35" />
</Grid.RowDefinitions>
<telerik:Label Content="User Name: " Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Grid.Row="0" MinHeight="23" HorizontalAlignment="Left" VerticalAlignment="Center" MinWidth="180" MaxWidth="180" >
<TextBox.Text>
<Binding Path="UserName" Mode="TwoWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True"/>
</TextBox.Text>
</TextBox>
<telerik:Label Content="First Name: " Grid.Column="2" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Grid.Column="3" Grid.Row="0" MinHeight="23" HorizontalAlignment="Left" VerticalAlignment="Center" MinWidth="180" MaxWidth="180">
<TextBox.Text>
<Binding Path="FirstName" Mode="TwoWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True"/>
</TextBox.Text>
</TextBox>
<telerik:Label Content="Last Name: " Grid.Column="4" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Grid.Column="5" Grid.Row="0" MinHeight="23" HorizontalAlignment="Left" VerticalAlignment="Center" MinWidth="180" MaxWidth="180">
<TextBox.Text>
<Binding Path="LastName" Mode="TwoWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True"/>
</TextBox.Text>
</TextBox>
<telerik:Label Content="Email: " Grid.Column="0" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Grid.Row="1" MinHeight="23" HorizontalAlignment="Left" VerticalAlignment="Center" MinWidth="180" MaxWidth="180">
<TextBox.Text>
<Binding Path="Email" Mode="TwoWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True"/>
</TextBox.Text>
</TextBox>
<telerik:Label Content="Active Status: " Grid.Column="2" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center" />
<telerik:RadComboBox x:Name="comBoxActiveStatus" Grid.Column="3" Grid.Row="1" MinHeight="23" MinWidth="180" HorizontalAlignment="Left" VerticalAlignment="Center"
SelectedItem="{Binding Path=ActiveStatus,
Converter={StaticResource ResourceKey=ActiveStatusConverter},
Mode=TwoWay,
ValidatesOnExceptions=True,
NotifyOnValidationError=True}">
</telerik:RadComboBox>
<telerik:Label Content="Role: " Grid.Column="4" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center" />
<telerik:RadComboBox x:Name="cmbRoles" DisplayMemberPath="RoleName"
Grid.Column="5"
Grid.ColumnSpan="3"
Grid.Row="1"
MinHeight="23"
HorizontalAlignment="Left"
ItemsSource="{Binding}"
Margin="5"
VerticalAlignment="Center"
MinWidth="180"
SelectedItem="{Binding RoleName}"
IsSynchronizedWithCurrentItem="True">
</telerik:RadComboBox>
<Button Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="3" Content="Save User" Width="100" />
<Button Grid.Column="4" Grid.Row="2" Grid.ColumnSpan="3" Content="Add User" Width="100" />
</Grid>
</StackPanel>
<Border CornerRadius="10" BorderThickness="5" Grid.Row="1" VerticalAlignment="Top" HorizontalAlignment="Center">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Content="Users" Grid.Row="0" Height="25" FontSize="14" HorizontalContentAlignment="Center" />
<telerik:RadGridView x:Name="usersDG" ItemsSource="{Binding Users}" AutoGenerateColumns="False" ShowGroupPanel="False" IsReadOnly="True">
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn DataMemberBinding="{Binding UserName}" Header="User Name" />
<telerik:GridViewDataColumn DataMemberBinding="{Binding FirstName}" Header="First Name" />
<telerik:GridViewDataColumn DataMemberBinding="{Binding LastName}" Header="Last Name" />
<telerik:GridViewDataColumn DataMemberBinding="{Binding Email}" Header="Email" />
<telerik:GridViewDataColumn DataMemberBinding="{Binding Role.RoleName}" Header="Role Name" />
<telerik:GridViewDataColumn DataMemberBinding="{Binding ActiveStatus, Converter={StaticResource ActiveStatusConverter}}" Header="Active Status" />
</telerik:RadGridView.Columns>
</telerik:RadGridView>
</Grid>
</Border>
</Grid>
采纳答案by PGallagher
Expanding and taking a different take on Hannish's Answer above, I too assume you are using a Master Details type arrangement, where you want the Details DataContext to be set to the DataGrid Selected Row.
扩展并采取不同的方式对上述 Hannish 的回答,我也假设您使用的是 Master Details 类型的排列,您希望将 Details DataContext 设置为 DataGrid Selected Row。
I also had alot of trouble with ComboBox Binding in this setup too.
在此设置中,我也遇到了 ComboBox 绑定的很多问题。
I don't use Telerik Controls for my applications, however I tend to create a Property for the DataGrid Selected Row, and bind my details to this.
我不为我的应用程序使用 Telerik 控件,但是我倾向于为 DataGrid 选定行创建一个属性,并将我的详细信息绑定到它。
The DataGrid XAML would be something like;
DataGrid XAML 类似于;
<DataGrid x:Name="grdResults"
DataContext="{Binding DataGridDataContextCollection}"
ItemsSource="{Binding}"
SelectedItem="{Binding DataContext.SelectedRow, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
I do it this way, as I have Behaviours I've set for the Rows which run off items in the DataGrid DataContext.
我是这样做的,因为我已经为在 DataGrid DataContext 中运行项目的行设置了行为。
I then have a Property for the Selected ComboBox Item also, and Bind the ComboBox to this.
然后我也有一个 Selected ComboBox Item 的属性,并将 ComboBox 绑定到这个。
For the ComboBox ItemSource, the issue is, that you have an ObservableCollection of Items which you need to Bind your ComboBox to, but these of course won't be a member of your DataGrid Selected Row, and in turn your details DataContext.
对于 ComboBox ItemSource,问题是,您需要将 ComboBox 绑定到一个 ObservableCollection 项目,但这些当然不会成为您的 DataGrid Selected Row 的成员,而反过来您的详细信息 DataContext。
So for Binding the ComboBox ItemSource and SelectedItem, you must refer to the DataContext of your View, rather than that of the Details.
因此,对于绑定 ComboBox ItemSource 和 SelectedItem,您必须引用 View 的 DataContext,而不是 Details 的 DataContext。
If you have it available in your DataGrid DataContext, also bind the ComboBox Text Property to the DataGrid SelectedRow Name value, assuming the two are the same! This helps update the DataGrid updated also.
如果您在 DataGrid DataContext 中有它可用,还要将 ComboBox Text 属性绑定到 DataGrid SelectedRow Name 值,假设两者相同!这有助于更新 DataGrid 也更新。
The XAML I use for the ComboBox is something like;
我用于 ComboBox 的 XAML 类似于;
<ComboBox x:Name="cmbRoles"
SelectedItem="{Binding DataContext.SelectedRole, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, NotifyOnValidationError=True}"
SelectedValuePath="Role_ID"
SelectedValue="{Binding Role_ID, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, NotifyOnValidationError=True}"
ItemsSource="{Binding DataContext.RoleItems, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
Text="{Binding RoleName, Mode=TwoWay}"
DisplayMemberPath="RoleName"
IsSynchronizedWithCurrentItem="True"
HorizontalAlignment="Left"/>
To be 100% sure, I then sync the ComboBox SelectedItem to the DataGrid SelectedRow by setting the DataGrid SelectedRow ID value from within your ComboBox SelectedItem Setter. This of course isn't strictly necessary.
为了 100% 确定,我然后通过在 ComboBox SelectedItem Setter 中设置 DataGrid SelectedRow ID 值将 ComboBox SelectedItem 同步到 DataGrid SelectedRow。这当然不是绝对必要的。
I hope this helps!
我希望这有帮助!
回答by Hannish
If I understood correctly, you have a RadGridView with all users, and some sort of Details form in which you edit the values for the selected row.
如果我理解正确的话,您有一个包含所有用户的 RadGridView,以及某种详细信息表单,您可以在其中编辑所选行的值。
So, you have to modify a couple of things:
所以,你必须修改一些东西:
1: The ItemsSource in the combobox is set to {Binding}, so it will just bind to the datacontext of its parent element to get the items list. In this case the parent is the Grid with the DataContext set (correctly) to the RadGrid's selected item (here: DataContext="{Binding ElementName=usersDG, Path=SelectedItem}", it's ok).
1:combobox中的ItemsSource设置为{Binding},所以它只会绑定到其父元素的datacontext来获取items列表。在这种情况下,父级是将 DataContext 设置(正确)到 RadGrid 的选定项的 Grid(这里:DataContext="{Binding ElementName=usersDG, Path=SelectedItem}",没关系)。
The problem is that you have to populate the ItemsSource of the ComboBox with the list of possible Roles. I usually use a static ObservableCollection for such lists (so I make sure they are the same all around the application). Something like this:
问题是您必须使用可能的角色列表填充 ComboBox 的 ItemsSource。我通常对此类列表使用静态 ObservableCollection(因此我确保它们在整个应用程序中都是相同的)。像这样的东西:
ItemsSource="{x:Static local:Lists.RolesList}"
ItemsSource="{x:Static local:Lists.RolesList}"
You may have an enum or something else, but the important thing there is that you populate the ItemsSource property with all the options that may be selected.
您可能有一个枚举或其他东西,但重要的是您用所有可能选择的选项填充 ItemsSource 属性。
2: Since you will populate the list in the combobox with Role objects, the SelectedItem must be bound to such an object, which has to exist as a public property (with INPC or a DependecyProperty) inside the User object. You need to set it up like this:
2:由于您将使用 Role 对象填充组合框中的列表,SelectedItem 必须绑定到这样的对象,该对象必须作为公共属性(使用 INPC 或 DependecyProperty)存在于 User 对象中。你需要这样设置:
SelectedItem="{Binding Role, Mode=TwoWay}"
SelectedItem="{绑定角色,模式=双向}"
Remember that the datacontext of your combo is an User object, as selected in the RadGrid. The user class must have a property Role.
请记住,组合的数据上下文是一个用户对象,如在 RadGrid 中选择的那样。用户类必须具有属性 Role。
I think that'll do it, let me know if you have any more problems. Best regards!
我想这样就可以了,如果您有任何问题,请告诉我。此致!

