如何在数据网格内绑定ComboBox? [英] How to Bind ComboBox inside a Datagrid?
问题描述
我有一个称为组的表,如下所示:
在上面的图片中,我认为您可能已经理解主键和外键存在于同一张表中。我认为这就是开发人员所谓的循环引用。
在MainWindow.xaml中,我有一个DataGrid,其中包含三列,即组名,父名,描述。 xaml看起来像:
< Window .......>
< Window.DataContext>
< self:MainWindowViewModel />
< /Window.DataContext>
< DataGrid ItemsSource = {Binding Groups} TabIndex = 1>
< DataGrid.Columns>
< DataGridTemplateColumn Header = Group Name Width = 2 *>
< DataGridTemplateColumn.CellTemplate>
< DataTemplate>
< TextBlock Text = {Binding GroupName} />
< / DataTemplate>
< /DataGridTemplateColumn.CellTemplate>
< DataGridTemplateColumn.CellEditingTemplate>
< DataTemplate>
< TextBox Text = {Binding GroupName} />
< / DataTemplate>
< /DataGridTemplateColumn.CellEditingTemplate>
< / DataGridTemplateColumn>
< DataGridTemplateColumn Header = Parent Width = 2 *>
< DataGridTemplateColumn.CellTemplate>
< DataTemplate>
< TextBlock Text = {Binding ParentID} />
< / DataTemplate>
< /DataGridTemplateColumn.CellTemplate>
< DataGridTemplateColumn.CellEditingTemplate>
< DataTemplate>
< ComboBox ItemsSource = {Binding DataContext.GroupsCollection,RelativeSource = {RelativeSource Mode = FindAncestor,AncestorType = {x:Type Window}}}
SelectedValue = {Binding ParentID}
DisplayMemberPath = GroupName />
< / DataTemplate>
< /DataGridTemplateColumn.CellEditingTemplate>
< / DataGridTemplateColumn>
< DataGridTemplateColumn Header = Description Width = 2 *>
< DataGridTemplateColumn.CellTemplate>
< DataTemplate>
< TextBlock Text = {绑定描述} />
< / DataTemplate>
< /DataGridTemplateColumn.CellTemplate>
< DataGridTemplateColumn.CellEditingTemplate>
< DataTemplate>
< TextBox文字= {绑定描述} />
< / DataTemplate>
< /DataGridTemplateColumn.CellEditingTemplate>
< / DataGridTemplateColumn>
< / power:PowerDataGrid.Columns>
< / power:PowerDataGrid>
< / Window>
现在我有一个名为MainWindowViewModel的ViewModel
公共类MainWindowViewModel:INotifyPropertyChanged
{
public MainWindowViewModel()
{
SampleDBContext sampleDBContext = new SampleDBContext();
Groups = new ObservableCollection< Group>();
GroupsCollection = new ObservableCollection< Group>(从sampleDBContext.g中的g中选择g);
}
私人ObservableCollection< Group> _groups;
public ObservableCollection< Group>组
{
获得
{
return _groups;
}
set
{
_groups = value;
OnPropertyChanged( Groups);
}
}
私人ObservableCollection< Group> _groupsCollection;
public ObservableCollection< Group> GroupsCollection
{
get
{
return _groupsCollection;
}
set
{
_groupsCollection = value;
OnPropertyChanged( GroupsCollection);
}
}
#region INotifyPropertyChanged
公共事件PropertyChangedEventHandler PropertyChanged;
受保护的无效OnPropertyChanged(字符串propertryName)
{
if(PropertyChanged!= null)
{
PropertyChanged(this,new PropertyChangedEventArgs(propertryName)) ;
}
}
#endregion
}
问题:
输出:
如上图所示,当我在父列中选择一个组后按TAB或Enter时,下一个单元格被聚焦,但是父列下的单元格有一个红色的轮廓,表示一些错误。而且单元格不会离开编辑模式。我在输出窗口中也遇到很多绑定错误。因此,我知道我的绑定不正确。有人可以帮我将 Combobox
绑定到 datagrid
内吗?
更新:
如果我按如下方式使用SelectedValuePath:
<组合框ItemsSource = {Binding DataContext.GroupsCollection,RelativeSource = {RelativeSource Mode = FindAncestor,AncestorType = {x:Type Window}}}
SelectedValue = {Binding ParentID} SelectedValuePath = {Binding GroupID}
DisplayMemberPath = GroupName />
然后错误消失了,单元格也离开了编辑模式。但是,然后TextBlock(它是celltemplate)始终保持为空。
解决了它。我不应该在SelectedValuePath中使用绑定。因此,现在我的代码应类似于:
< ComboBox ItemsSource = {Binding DataContext.GroupsCollection,RelativeSource = {RelativeSource Mode = FindAncestor,AncestorType = {x:Type窗口}}}
SelectedValue = {Binding ParentID} SelectedValuePath = GroupID
DisplayMemberPath = GroupName />
现在的问题是:
我明白了由于我对CellTemplate的绑定,在完成编辑模式后,ComboBox的SelectedValue的ID(但我想用名称代替ID):
< DataGridTemplateColumn Header = Parent Width = 2 *>
< DataGridTemplateColumn.CellTemplate>
< DataTemplate>
< TextBlock Text = {Binding ParentID} />
< / DataTemplate>
< /DataGridTemplateColumn.CellTemplate>
< DataGridTemplateColumn.CellEditingTemplate>
< DataTemplate>
< ComboBox ItemsSource = {Binding DataContext.GroupsCollection,RelativeSource = {RelativeSource Mode = FindAncestor,AncestorType = {x:Type Window}}}}
SelectedValue = {Binding ParentID} SelectedValuePath = GroupID
DisplayMemberPath = GroupName />
< / DataTemplate>
< /DataGridTemplateColumn.CellEditingTemplate>
< / DataGridTemplateColumn>
所以我创建了一个转换器,如下所示:
公共类GroupIDToGroupName:IValueConverter
{
公共对象Convert(对象值,类型targetType,对象参数,System.Globalization.CultureInfo文化)
{
if(value!= null)
{
SampleDBContext sampleDBContext = new SampleDBContext();
返回(从sampleDBContext.Groups
中的g返回,其中g.GroupID ==(int)value
选择g.GroupName).FirstOrDefault();
}
其他
{
返回;
}
}
公共对象ConvertBack(对象值,类型targetType,对象参数,System.Globalization.CultureInfo文化)
{
SampleDBContext sampleDBContext =新的SampleDBContext();
返回(从sampleDBContext.Groups
中的g返回,其中g.GroupName ==(字符串)值
选择g.GroupID).FirstOrDefault();
}
}
我在App.xaml中将该转换器声明为:
< self:GroupIDToGroupName x:Key = GroupIDToGroupNameConveerter />
现在,我的Cell模板看起来像:
< TextBlock Text = {Binding ParentID,Converter = {StaticResource GroupIDToGroupNameConveerter}} />
我不知道我是否以正确的方式解决了我的问题。但是它的工作!!!!!!!
如果有人有个好主意,请分享...........
I have a table called groups as shown below :
After looking at the image above I think you might have understood that primary key and foreign key exist in the same table. I think this is what developers call cyclic reference.
In MainWindow.xaml I have a DataGrid which contains three columns namely Group Name, Parent Name, Description. The xaml looks like :
<Window .......>
<Window.DataContext>
<self:MainWindowViewModel />
</Window.DataContext>
<DataGrid ItemsSource="{Binding Groups}" TabIndex="1">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Group Name" Width="2*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding GroupName}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding GroupName}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Parent" Width="2*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding ParentID}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding DataContext.GroupsCollection, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"
SelectedValue="{Binding ParentID}"
DisplayMemberPath="GroupName"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Description" Width="2*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Description}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding Description}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</power:PowerDataGrid.Columns>
</power:PowerDataGrid>
</Window>
Now I have a ViewModel called MainWindowViewModel
public class MainWindowViewModel : INotifyPropertyChanged
{
public MainWindowViewModel()
{
SampleDBContext sampleDBContext = new SampleDBContext();
Groups = new ObservableCollection<Group>();
GroupsCollection = new ObservableCollection<Group>(from g in sampleDBContext.Groups select g);
}
private ObservableCollection<Group> _groups;
public ObservableCollection<Group> Groups
{
get
{
return _groups;
}
set
{
_groups = value;
OnPropertyChanged("Groups");
}
}
private ObservableCollection<Group> _groupsCollection;
public ObservableCollection<Group> GroupsCollection
{
get
{
return _groupsCollection;
}
set
{
_groupsCollection = value;
OnPropertyChanged("GroupsCollection");
}
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertryName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertryName));
}
}
#endregion
}
Problems :
Output :
As you can see in the above image when I press TAB or Enter after selecting a group in Parent Column the next cell is focused but cell Under Parent Column has a red Outline indicating some error. Also cell does not leave edit mode. Also I get lot of binding errors in output window. So, I know that my binding is incorrect. Can somebody help me to bind Combobox
inside a datagrid
?
Update:
If I use the SelectedValuePath as below :
<ComboBox ItemsSource="{Binding DataContext.GroupsCollection, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"
SelectedValue="{Binding ParentID}" SelectedValuePath="{Binding GroupID}"
DisplayMemberPath="GroupName" />
Then the error goes away and cell also leaves edit mode. But then TextBlock(which is celltemplate) always remains empty.
Solved it. I should not use Binding in SelectedValuePath. So, now my code should look something like :
<ComboBox ItemsSource="{Binding DataContext.GroupsCollection, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"
SelectedValue="{Binding ParentID}" SelectedValuePath="GroupID"
DisplayMemberPath="GroupName" />
Now problem is :
I get ID (but I want to have name instead of ID) of the SelectedValue of ComboBox after the edit mode is finished due to my binding of CellTemplate as below:
<DataGridTemplateColumn Header="Parent" Width="2*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding ParentID}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding DataContext.GroupsCollection, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"
SelectedValue="{Binding ParentID}" SelectedValuePath="GroupID"
DisplayMemberPath="GroupName" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
So I created a converter as below :
public class GroupIDToGroupName : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null)
{
SampleDBContext sampleDBContext = new SampleDBContext();
return (from g in sampleDBContext.Groups
where g.GroupID == (int)value
select g.GroupName).FirstOrDefault();
}
else
{
return "";
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
SampleDBContext sampleDBContext = new SampleDBContext();
return (from g in sampleDBContext.Groups
where g.GroupName == (string)value
select g.GroupID).FirstOrDefault();
}
}
And I declared that converter in App.xaml as :
<self:GroupIDToGroupName x:Key="GroupIDToGroupNameConveerter" />
Now, my Cell template looks like :
<TextBlock Text="{Binding ParentID, Converter={StaticResource GroupIDToGroupNameConveerter}}" />
I don't know that I have solved my problem in the right way or not. But its working!!!!
If anybody has a good idea then please share...........
这篇关于如何在数据网格内绑定ComboBox?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!