引子
在项目中需要使用DataGrid控件中的DataGridComboBoxColumn
列来实现绑定下拉列表功能。
未实现功能示例代码
XAML代码:
<Window x:Class="DGComboBoxDemo.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:DGComboBoxDemo"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<local:DC_Main x:Key="DC"/>
</Window.Resources>
<DataGrid AutoGenerateColumns="False" CanUserAddRows="False" Name="dg" DataContext="{Binding Source={StaticResource DC}}" ItemsSource="{Binding UnitItems}">
<DataGrid.Columns>
<DataGridTextColumn Header="名称" Binding="{Binding Name}" Width="100"/>
<DataGridTextColumn Header="当前值" Binding="{Binding Step}" Width="80"/>
<DataGridComboBoxColumn Header="选项" ItemsSource="{Binding StepItems}" DisplayMemberPath="Tip" SelectedValuePath="Step" Width="*"/>
</DataGrid.Columns>
</DataGrid>
</Window>
C#代码如下:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var dc = dg.DataContext as DC_Main;
var unit1 = new UnitItem { Name = "单元1", Step = 1 };
unit1.StepItems.Add(new StepItem { Tip = "就绪", Step = 0 });
unit1.StepItems.Add(new StepItem { Tip = "初始化", Step = 1 });
var unit2 = new UnitItem { Name = "单元2", Step = 0 };
unit2.StepItems.Add(new StepItem { Tip = "开始", Step = 0 });
unit2.StepItems.Add(new StepItem { Tip = "结束", Step = 1 });
dc.UnitItems.Add(unit1);
dc.UnitItems.Add(unit2);
}
}
public class StepItem
{
public string Tip { get; set; }
public ushort Step { get; set; }
}
public class UnitItem
{
public string Name { get; set; }
public ushort Step { get; set; }
public ObservableCollection<StepItem> StepItems { get; set; } = new ObservableCollection<StepItem>();
}
public class DC_Main
{
public ObservableCollection<UnitItem> UnitItems { get; set; } = new ObservableCollection<UnitItem>();
}
运行效果
运行软件发现第三列未显示为下拉列表,用户点击选项列对应内容,显示的下拉表为空,未能达到预定效果。通过网络搜索DataGridComboBoxColumn
的相关示例,发现大部分ItemsSource
为静态绑定,无法实现动态列表内容填充功能。
替代方案
因无法使用原生的DataGridComboBoxColumn
数据列项实现下拉列表功能,只好使用DataGridTemplateColumn
+ComboBox
组合方案实现此功能,最终运行效果如下。
XAML代码
<Window x:Class="DGComboBoxDemo.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:DGComboBoxDemo"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<local:DC_Main x:Key="DC"/>
</Window.Resources>
<DataGrid AutoGenerateColumns="False" CanUserAddRows="False" Name="dg" DataContext="{Binding Source={StaticResource DC}}" ItemsSource="{Binding UnitItems}">
<DataGrid.Columns>
<DataGridTextColumn Header="名称" Binding="{Binding Name}" Width="100"/>
<DataGridTextColumn Header="当前值" Binding="{Binding CurStep}" Width="80"/>
<DataGridTemplateColumn Header="选项" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding StepItems}" DisplayMemberPath="Tip" SelectedValuePath="Step" SelectedValue="{Binding SelStep}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Window>
最终解决方案
通过不懈努力,终于将此问题解决!!!
XAML
<Window x:Class="DGComboBoxDemo.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:DGComboBoxDemo"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<local:DC_Main x:Key="DC"/>
</Window.Resources>
<DataGrid AutoGenerateColumns="False" CanUserAddRows="False" Name="dg" DataContext="{Binding Source={StaticResource DC}}" ItemsSource="{Binding UnitItems}">
<DataGrid.Columns>
<DataGridTextColumn Header="名称" Binding="{Binding Name}" Width="100"/>
<DataGridTextColumn Header="选项1值" Binding="{Binding CurStep}" Width="80"/>
<DataGridTemplateColumn Header="选项" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding StepItems1}" DisplayMemberPath="Tip" SelectedValuePath="Step" SelectedValue="{Binding CurStep, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="选项2值" Binding="{Binding SelStep}" Width="80"/>
<DataGridComboBoxColumn Header="选项2" Width="*" SelectedValueBinding="{Binding SelStep, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding StepItems2}"/>
<Setter Property="DisplayMemberPath" Value="Tip"/>
<Setter Property="SelectedValuePath" Value="Step"/>
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding StepItems2}"/>
<Setter Property="DisplayMemberPath" Value="Tip"/>
<Setter Property="SelectedValuePath" Value="Step"/>
</Style>
</DataGridComboBoxColumn.ElementStyle>
</DataGridComboBoxColumn>
</DataGrid.Columns>
</DataGrid>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var dc = dg.DataContext as DC_Main;
var unit1 = new UnitItem { Name = "单元1", CurStep = 1 };
unit1.StepItems1.Add(new StepItem { Tip = "就绪", Step = 0 });
unit1.StepItems1.Add(new StepItem { Tip = "初始化", Step = 1 });
unit1.StepItems2.Add(new StepItem { Tip = "开始", Step = 0 });
unit1.StepItems2.Add(new StepItem { Tip = "结束", Step = 1 });
var unit2 = new UnitItem { Name = "单元2", CurStep = 0 };
unit2.StepItems1.Add(new StepItem { Tip = "就绪", Step = 0 });
unit2.StepItems1.Add(new StepItem { Tip = "初始化", Step = 1 });
unit2.StepItems2.Add(new StepItem { Tip = "开始", Step = 0 });
unit2.StepItems2.Add(new StepItem { Tip = "结束", Step = 1 });
dc.UnitItems.Add(unit1);
dc.UnitItems.Add(unit2);
}
}
public class VMBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
// This method is called by the Set accessor of each property.
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
public void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class StepItem
{
public string Tip { get; set; }
public ushort Step { get; set; }
}
public class UnitItem : VMBase
{
public string Name { get; set; }
private ushort _CurStepp;
public ushort CurStep {
get { return _CurStepp; }
set {
_CurStepp = value;
NotifyPropertyChanged();
}
}
private ushort _SelStep;
public ushort SelStep
{
get { return _SelStep; }
set
{
_SelStep = value;
NotifyPropertyChanged();
}
}
public ObservableCollection<StepItem> StepItems1 { get; set; } = new ObservableCollection<StepItem>();
public ObservableCollection<StepItem> StepItems2 { get; set; } = new ObservableCollection<StepItem>();
}
public class DC_Main
{
public ObservableCollection<UnitItem> UnitItems { get; set; } = new ObservableCollection<UnitItem>();
}