如何在WPF中的数据网格内处理组合框? [英] How do I work on combobox inside a datagrid in WPF?
问题描述
我有一个组合框,其中包含从数据库填充的数据。我可以使用组合框的绑定到文本框中,如:
但是当第一列应用相同时,组合框功能没有开火,它表现得像另一个文本框
我尝试过:
< DataGridTemplateColumn Header =ProductNameClipboardContentBinding ={Binding ProductName}>
< DataGridTemplateColumn.CellTemplate>
< DataTemplate>
< TextBox Text ={Binding ProductName,NotifyOnTargetUpdated = True,UpdateSourceTrigger = PropertyChanged}> < /文本框>
< / DataTemplate>
< /DataGridTemplateColumn.CellTemplate>
< DataGridTemplateColumn.CellEditingTemplate>
< DataTemplate>
< ComboBox IsEditable =TrueName =cmbProductNameItemsSource ={StaticResource ProductNames}SelectedItem ={Binding ProductName,Mode = TwoWay,UpdateSourceTrigger = PropertyChanged}IsDropDownOpen =False>
< / ComboBox>
< / DataTemplate>
< /DataGridTemplateColumn.CellEditingTemplate>
< / DataGridTemplateColumn>
以下是您的工作示例...
首先,数据绑定通知的基本类INotifyPropertyChanged
:
< span class =code-keyword> public abstract class ObservableBase:INotifyPropertyChanged
{
public void 设置< TValue>( ref TValue字段,TValue newValue,
[CallerMemberName] 字符串 propertyName = )
{
if (EqualityComparer< TValue> .Default.Equals (字段,默认(TValue))
||!field.Equals(newValue))
{
field = newValue;
PropertyChanged?.Invoke( this , new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged ;
}
接下来我们需要一个数据模型来保存每一行进行编辑:
< span class =code-keyword> public class PersonModel:ObservableBase
{
private string name;
public string 名称
{
获取 {返回名称; }
set {Set( ref name,值跨度>); }
}
private int age;
public int 年龄
{
获取 {返回年龄; }
set {Set( ref age,值跨度>); }
}
私人 int 收入;
public int 收入
{
获取 {返回收入; }
set {Set( ref income,值跨度>); }
}
}
接下来我们需要一个ViewModel将我们的数据链接到视图:
< pre lang =c#> class MainViewModel
{
public MainViewModel()
{
Mock();
}
私人 void 模拟()
{
for ( int i = 20 ; i < 120 ; i ++)
{
AgeRange。加入(I)
}
for ( int i = 0 ; i < 100 ; i ++)
{
IncomeRange.Add( 10000 + 10 * i);
}
for ( int i = 0 ; i < 100 ; i ++)
{
People.Add( new PersonModel
{
Name =
人{i},
年龄= AgeRange [rand.Next( 0 ,AgeRange.Count - 1 )],
收入= IncomeRange [rand.Next( 0 ,IncomeRange.Count - 1 )]
});
}
}
私人随机rand = new 随机();
public ObservableCollection< PersonModel>人{获取; }
= new ObservableCollection< PersonModel>();
public ObservableCollection< int> AgeRange { get ; }
= new ObservableCollection< int>();
public ObservableCollection< int> IncomeRange { get ; }
= new ObservableCollection< int>();
}
现在我们可以查看:
< 窗口 x:类 = DataGridColumnComboBox.MainWindow
xmlns = http://schemas.microsoft.com/winfx/2006/xaml/presentation
< span class =code-attribute> xmlns:x = http: //schemas.microsoft.com/winfx/2006/xaml\"
xmlns:d = < span class =code-keyword> http://schemas.microsoft.com/expression/blend/2008
< span class =code-attribute> xmlns:mc = http://schemas.openxmlformats.org/markup-compatibility/2006
xmlns:local = clr-namespace:DataGridColumnComboBox
mc:可忽略 = < span class =code-keyword> d
< span class =code-attribute> 标题 = MainWindow 高度 = 450 宽度 = 800 < span class =code-keyword>>
< Window.DataContext >
< local: MainViewModel / >
< /Window.DataContext >
< DataGrid ItemsSource = {Binding People}
< span class =code-attribute> AutoGenerateColumns = False
GridLinesVisibility = 无 保证金 = 10 >
< DataGrid.Columns >
< DataGridTextColumn 标题 = 名称 绑定 = {Binding Name} 宽度 = 200 / >
< < span class =code-leadattribute> DataGridComboBoxColumn 标题 = 年龄 宽度 = 75
< span class =code-attribute> SelectedItemBinding = {Binding Age} >
< DataGridComboBoxColumn.ElementStyle >
< < span class =code-leadattribute>样式 TargetType =跨度> <跨度class =code-keyword> ComboBox >
< Setter 属性 = ItemsSource
值 = {Binding RelativeSource = {RelativeSource
FindAncestor,
AncestorType = {x:Type Window },
Path = DataContext.AgeRange} / >
< / Style >
< /DataGridComboBoxColumn.ElementStyle>
< DataGridComboBoxColumn.EditingElementStyle >
< 样式 TargetType = ComboBox >
< Setter 属性 = ItemsSource < span class =code-attribute>
< span class =code-attribute> 值 = {Binding RelativeSource = {RelativeSource
FindAncestor,
AncestorType = {x:Type Window}},
Path = DataContext.AgeRange} / < span class =code-keyword>>
< / Style >
< / DataGridComboBoxColumn.EditingElementStyle >
< span class =code-keyword>< / DataGridComboBoxColumn >
< DataGridComboBoxColumn 标题 = 收入 宽度 = 150
SelectedItemBinding = {绑定收入} >
< DataGridComboBoxColumn.ElementStyle >
< 样式 TargetType = ComboBox >
< Setter Property = ItemsSource
值 = {Binding RelativeSource = {RelativeSource
FindAncestor,
AncestorType = {x:Type Window} },
Path = DataContext.IncomeRange} / >
< / Style >
< / DataGridComboBoxColumn.ElementStyle >
< DataGridComboBoxColumn.EditingElementStyle >
< 样式 TargetType = ComboBox >
< span class =code-keyword>< Setter 属性 = ItemsSource
< span class =code-attribute> 值 = {Binding RelativeSource = {RelativeSource
FindAncestor,
AncestorType = {x:Type Window}},
Path = DataContext.IncomeRange} / < span class =code-keyword>>
< / Style >
< / DataGridComboBoxColumn。 EditingElementStyle >
< / DataGridComboBoxColumn >
< / DataGrid.Columns >
< / DataGrid >
< / Window >
视图非常详细。 You can simplify the code and reduce the typos by using styles:
<DataGrid ItemsSource=\"{Binding People}\"
AutoGenerateColumns=\"False\"
GridLinesVisibility=\"None\" Margin=\"10\">
<DataGrid.Resources>
<Style TargetType=\"ComboBox\" x:Key=\"AgeRangeStyle\">
<Setter Property=\"ItemsSource\"
Value=\"{Binding RelativeSource={RelativeSource
FindAncestor,
AncestorType={x:Type Window}},
Path=DataContext.AgeRange}\"/>
</Style>
<Style TargetType=\"ComboBox\" x:Key=\"IncomeRangeStyle\">
<Setter Property=\"ItemsSource\"
Value=\"{Binding RelativeSource={RelativeSource
FindAncestor,
AncestorType={x:Type Window}},
Path=DataContext.IncomeRange}\"/>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header=\"Name\" Binding=\"{Binding Name}\" Width=\"200\"/>
<DataGridComboBoxColumn Header=\"Age\" Width=\"75\"
SelectedItemBinding=\"{Binding Age}\"
ElementStyle=\"{StaticResource AgeRangeStyle}\"
EditingElementStyle=\"{StaticResource AgeRangeStyle}\"/>
<DataGridComboBoxColumn Header=\"Income\" Width=\"75\"
SelectedItemBinding=\"{Binding Income}\"
ElementStyle=\"{StaticResource IncomeRangeStyle}\"
< span class =code-attribute> EditingElementStyle=\"{StaticResource
IncomeRangeStyle}\"/>
</DataGrid.Columns>
</DataGrid>
Enjoy!
UPDATE: Changed first column to use a ComboBox editor... see OP comments below.
MainVi ewModel:
class MainViewModel
{
public MainViewModel()
{
Mock();
}
private void Mock()
{
for (int i = 20; i < 120; i++)
{
AgeRange.Add(i);
}
for (int i = 0; i < 100; i++)
{
IncomeRange.Add(10000 + 10 * i);
}
for (int i = 0; i < 100; i++)
{
People.Add(new PersonModel
{
Name =
\"Person {i}\",
Age = AgeRange[rand.Next(0, AgeRange.Count - 1)],
Income = IncomeRange[rand.Next(0, IncomeRange.Count - 1)]
});
}
Names = new ObservableCollection<string>(People.Select(x => x.Name));
}
private Random rand = new Random();
public ObservableCollection<PersonModel> People { get; }
= new ObservableCollection<PersonModel>();
public ObservableCollection<int> AgeRange { get; }
= new ObservableCollection<int>();
public ObservableCollection<int> IncomeRange { get; }
= new ObservableCollection<int>();
public ObservableCollection<string> Names { get; private set ; }
}
And the View’s DataGrid:
<DataGrid ItemsSource=\"{Binding People}\"
AutoGenerateColumns=\"False\"
GridLinesVisibility=\"None\" Margin=\"10\">
<DataGrid.Resources>
<Style TargetType=\"ComboBox\" x:Key=\"NamesStyle\">
<Setter Property=\"ItemsSource\"
Value=\"{Binding RelativeSource={RelativeSource
FindAncestor,
AncestorType={x:Type Window}},
Path=DataContext.Names}\"/>
</Style>
<Style TargetType=\"ComboBox\" x:Key=\"AgeRangeStyle\">
<Setter Property=\"ItemsSource\"
Value=\"{Binding RelativeSource={RelativeSource
FindAncestor,
AncestorType={x:Type Window}},
Path=DataContext.AgeRange}\"/>
</Style>
<Style TargetType=\"ComboBox\" x:Key=\"IncomeRangeStyle\">
<Setter Property=\"ItemsSource\"
Value=\"{Binding RelativeSource={RelativeSource
FindAncestor,
AncestorType={x:Type Window}},
Path=DataContext.IncomeRange}\"/>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<!--<DataGridTextColumn Header=\"Name\" Binding=\"{Binding Name}\" Width=\"200\"/>-->
<DataGridComboBoxColumn Header=\"Name\" Width=\"75\"
SelectedItemBinding=\"{Binding Name}\"
ElementStyle=\"{StaticResource NamesStyle}\"
EditingElementStyle=\"{StaticResource NamesStyle}\"/>
<DataGridComboBoxColumn Header=\"Age\" Width=\"75\"
SelectedItemBinding=\"{Binding Age}\"
ElementStyle=\"{StaticResource AgeRangeStyle}\"
EditingElementStyle=\"{StaticResource AgeRangeStyle}\"/>
<DataGridComboBoxColumn Header=\"Income\" Width=\"75\"
SelectedItemBinding=\"{Binding Income}\" $b $b
ElementStyle=\"{StaticResource IncomeRangeStyle}\"
EditingElementStyle=\"{StaticResource IncomeRangeStyle}\"/>
</DataGrid.Columns< span class=\"code-keyword\">>
</DataGrid>
ComboBox selection works fine for the first column... Enjoy!
I have a combobox that has data that is populated from Database. I can use the binding of combobox into text box like :
But when the same is applied as the 1st column, the combobox feature is not firing, it behaves just as another textbox
What I have tried:
<DataGridTemplateColumn Header="ProductName" ClipboardContentBinding="{Binding ProductName}"> <DataGridTemplateColumn.CellTemplate > <DataTemplate > <TextBox Text="{Binding ProductName, NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged}" > </TextBox> </DataTemplate> </DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellEditingTemplate> <DataTemplate> <ComboBox IsEditable="True" Name="cmbProductName" ItemsSource="{StaticResource ProductNames}" SelectedItem="{Binding ProductName , Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" IsDropDownOpen="False" > </ComboBox> </DataTemplate> </DataGridTemplateColumn.CellEditingTemplate> </DataGridTemplateColumn>
Here is a working example for you...
First, a base class forINotifyPropertyChanged
for DataBinding notifications:
public abstract class ObservableBase : INotifyPropertyChanged { public void Set<TValue>(ref TValue field, TValue newValue, [CallerMemberName] string propertyName = "") { if (EqualityComparer<TValue>.Default.Equals(field, default(TValue)) || !field.Equals(newValue)) { field = newValue; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } public event PropertyChangedEventHandler PropertyChanged; }
Next we need a data model to hold each row for editing:
public class PersonModel : ObservableBase { private string name; public string Name { get { return name; } set { Set(ref name, value); } } private int age; public int Age { get { return age; } set { Set(ref age, value); } } private int income; public int Income { get { return income; } set { Set(ref income, value); } } }
Next we need to have a ViewModel to link our data to the view:
class MainViewModel { public MainViewModel() { Mock(); } private void Mock() { for (int i = 20; i < 120; i++) { AgeRange.Add(i); } for (int i = 0; i < 100; i++) { IncomeRange.Add(10000 + 10 * i); } for (int i = 0; i < 100; i++) { People.Add(new PersonModel { Name =
"Person {i}", Age = AgeRange[rand.Next(0, AgeRange.Count - 1)], Income = IncomeRange[rand.Next(0, IncomeRange.Count - 1)] }); } } private Random rand = new Random(); public ObservableCollection<PersonModel> People { get; } = new ObservableCollection<PersonModel>(); public ObservableCollection<int> AgeRange { get; } = new ObservableCollection<int>(); public ObservableCollection<int> IncomeRange { get; } = new ObservableCollection<int>(); }
Now we can do the View:
<Window x:Class="DataGridColumnComboBox.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:DataGridColumnComboBox" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Window.DataContext> <local:MainViewModel/> </Window.DataContext> <DataGrid ItemsSource="{Binding People}" AutoGenerateColumns="False" GridLinesVisibility="None" Margin="10"> <DataGrid.Columns> <DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="200"/> <DataGridComboBoxColumn Header="Age" Width="75" SelectedItemBinding="{Binding Age}"> <DataGridComboBoxColumn.ElementStyle> <Style TargetType="ComboBox"> <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.AgeRange}"/> </Style> </DataGridComboBoxColumn.ElementStyle> <DataGridComboBoxColumn.EditingElementStyle> <Style TargetType="ComboBox"> <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.AgeRange}"/> </Style> </DataGridComboBoxColumn.EditingElementStyle> </DataGridComboBoxColumn> <DataGridComboBoxColumn Header="Income" Width="150" SelectedItemBinding="{Binding Income}"> <DataGridComboBoxColumn.ElementStyle> <Style TargetType="ComboBox"> <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.IncomeRange}"/> </Style> </DataGridComboBoxColumn.ElementStyle> <DataGridComboBoxColumn.EditingElementStyle> <Style TargetType="ComboBox"> <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.IncomeRange}"/> </Style> </DataGridComboBoxColumn.EditingElementStyle> </DataGridComboBoxColumn> </DataGrid.Columns> </DataGrid> </Window>
The view is quite verbose. You can simplify the code and reduce the typos by using styles:
<DataGrid ItemsSource="{Binding People}" AutoGenerateColumns="False" GridLinesVisibility="None" Margin="10"> <DataGrid.Resources> <Style TargetType="ComboBox" x:Key="AgeRangeStyle"> <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.AgeRange}"/> </Style> <Style TargetType="ComboBox" x:Key="IncomeRangeStyle"> <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.IncomeRange}"/> </Style> </DataGrid.Resources> <DataGrid.Columns> <DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="200"/> <DataGridComboBoxColumn Header="Age" Width="75" SelectedItemBinding="{Binding Age}" ElementStyle="{StaticResource AgeRangeStyle}" EditingElementStyle="{StaticResource AgeRangeStyle}"/> <DataGridComboBoxColumn Header="Income" Width="75" SelectedItemBinding="{Binding Income}" ElementStyle="{StaticResource IncomeRangeStyle}" EditingElementStyle="{StaticResource IncomeRangeStyle}"/> </DataGrid.Columns> </DataGrid>
Enjoy!
UPDATE: Changed first column to use a ComboBox editor... see OP comments below.
MainViewModel:
class MainViewModel { public MainViewModel() { Mock(); } private void Mock() { for (int i = 20; i < 120; i++) { AgeRange.Add(i); } for (int i = 0; i < 100; i++) { IncomeRange.Add(10000 + 10 * i); } for (int i = 0; i < 100; i++) { People.Add(new PersonModel { Name =
"Person {i}", Age = AgeRange[rand.Next(0, AgeRange.Count - 1)], Income = IncomeRange[rand.Next(0, IncomeRange.Count - 1)] }); } Names = new ObservableCollection<string>(People.Select(x => x.Name)); } private Random rand = new Random(); public ObservableCollection<PersonModel> People { get; } = new ObservableCollection<PersonModel>(); public ObservableCollection<int> AgeRange { get; } = new ObservableCollection<int>(); public ObservableCollection<int> IncomeRange { get; } = new ObservableCollection<int>(); public ObservableCollection<string> Names { get; private set; } }
And the View's DataGrid:
<DataGrid ItemsSource="{Binding People}" AutoGenerateColumns="False" GridLinesVisibility="None" Margin="10"> <DataGrid.Resources> <Style TargetType="ComboBox" x:Key="NamesStyle"> <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Names}"/> </Style> <Style TargetType="ComboBox" x:Key="AgeRangeStyle"> <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.AgeRange}"/> </Style> <Style TargetType="ComboBox" x:Key="IncomeRangeStyle"> <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.IncomeRange}"/> </Style> </DataGrid.Resources> <DataGrid.Columns> <!--<DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="200"/>--> <DataGridComboBoxColumn Header="Name" Width="75" SelectedItemBinding="{Binding Name}" ElementStyle="{StaticResource NamesStyle}" EditingElementStyle="{StaticResource NamesStyle}"/> <DataGridComboBoxColumn Header="Age" Width="75" SelectedItemBinding="{Binding Age}" ElementStyle="{StaticResource AgeRangeStyle}" EditingElementStyle="{StaticResource AgeRangeStyle}"/> <DataGridComboBoxColumn Header="Income" Width="75" SelectedItemBinding="{Binding Income}" ElementStyle="{StaticResource IncomeRangeStyle}" EditingElementStyle="{StaticResource IncomeRangeStyle}"/> </DataGrid.Columns> </DataGrid>
ComboBox selection works fine for the first column... Enjoy!
这篇关于如何在WPF中的数据网格内处理组合框?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!