在DataGrid中绑定多列组合框的选定值

时间:2014-07-22 20:20:20

标签: c# wpf xaml datagrid combobox

工作示例:

我有一个名为groups的表,如下所示:

enter image description here

在查看上图后,我想您可能已经理解主键和外键存在于同一个表中。我认为这就是开发人员所说的循环引用。

在MainWindow.xaml中,我有一个DataGrid,它包含三列,即Group Name,Parent Name,Description。 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, Converter={StaticResource GroupIDToGroupNameConverter}}" />
                    </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>

            <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>

现在我有一个名为MainWindowViewModel

的ViewModel
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
}

GroupIDToGroupName.cs // Converter

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();
    }
}

在App.xaml中:

<self:GroupIDToGroupName x:Key="GroupIDToGroupNameConveerter" />

我的案例(与上面的示例非常相似):

我只想在DataGrid中使用多列ComboBox而不是简单的ComboBox。

我有两张桌子:

enter image description here

现在我完全按照上面提到的代码设置了我的代码。

我添加了一个名为GroupIDAndNameWithCorrespondingEffect的额外类,如:

public class GroupIDAndNameWithCorrespondingEffect : INotifyPropertyChanged
{
    private int _groupID;
    public int GroupID
    {
        get
        {
            return _groupID;
        }

        set
        {
            _groupID = value;
            OnPropertyChanged("GroupID");
        }
    }

    private string _groupName;
    public string GroupName
    {
        get
        {
            return _groupName;
        }

        set
        {
            _groupName = value;
            OnPropertyChanged("GroupName");
        }
    }

    private string _correspondingEffect;
    public string CorrespondingEffect
    {
        get
        {
            return _correspondingEffect;
        }

        set
        {
            _correspondingEffect = value;
            OnPropertyChanged("CorrespondingEffect");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

我的ViewModel中的更改:

我删除了属性GroupsCollection及其所有引用,并添加了一个名为GroupIDAndNamesWithCorrespondingEffects的新属性,如下所示:

private ObservableCollection<GroupIDAndNameWithCorrespondingEffect> _groupIDAndNamesWithCorrespondingEffects;
public ObservableCollection<GroupIDAndNameWithCorrespondingEffect> GroupIDAndNamesWithCorrespondingEffects
{
    get
    {
        return _groupIDAndNamesWithCorrespondingEffects;
    }
    set
    {
        _groupIDAndNamesWithCorrespondingEffects = value;
        OnPropertyChanged("GroupIDAndNamesWithCorrespondingEffects");
    }
}

在构造函数中:

List<GroupIDAndNameWithCorrespondingEffect> _GroupIDAndNamesWithCorrespondingEffects = (
                                                                                                 from g in sampleDBContext.Groups
                                                                                                 select new GroupIDAndNameWithCorrespondingEffect
                                                                                                 {
                                                                                                     GroupID = g.GroupID,
                                                                                                     GroupName = g.GroupName,
                                                                                                     CorrespondingEffect = g.Effect.Effect1
                                                                                                 }
                                                                                             ).ToList();

            GroupIDAndNamesWithCorrespondingEffects
                = new ObservableCollection<GroupIDAndNameWithCorrespondingEffect>(
                                                                                _GroupIDAndNamesWithCorrespondingEffects.Where
                                                                                    (
                                                                                        u => !GetAllChildren(25)
                                                                                                .Select(x => x.GroupID)
                                                                                                .Contains(u.GroupID)
                                                                                    ).ToList()
                                                                            );

在我的MainWindow.xaml中,我添加了如下资源:

<Window.Resources>
    <CollectionViewSource x:Key="GroupNamesWithCorrespondingEffectsCollection" Source="{Binding GroupIDAndNamesWithCorrespondingEffects}" />    
</Window.Resources>

Inside Grid的资源:

    <Grid.Resources>

        <CompositeCollection x:Key="Items">
            <ComboBoxItem IsEnabled="False" Background="#FF2A2A2A" Foreground="White">
                <Grid TextElement.FontWeight="Bold" >
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition SharedSizeGroup="A" />
                        <ColumnDefinition Width="50" />
                        <ColumnDefinition SharedSizeGroup="B" />
                    </Grid.ColumnDefinitions>
                    <Grid.Children>
                        <TextBlock Grid.Column="0" Text="Group Name" />
                        <TextBlock Grid.Column="2" Text="Effect" />
                    </Grid.Children>
                </Grid>
            </ComboBoxItem>
            <CollectionContainer Collection="{Binding Source={StaticResource GroupNamesWithCorrespondingEffectsCollection}}" />
        </CompositeCollection>

        <DataTemplate DataType="{x:Type self:GroupIDAndNameWithCorrespondingEffect}">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition SharedSizeGroup="A" />
                    <ColumnDefinition Width="50" />
                    <ColumnDefinition SharedSizeGroup="B" />
                </Grid.ColumnDefinitions>
                <Grid.Children>
                    <TextBlock Grid.Column="0" Text="{Binding GroupName}" />
                    <TextBlock Grid.Column="2" Text="{Binding CorrespondingEffect}" />
                </Grid.Children>
            </Grid>
        </DataTemplate>

    </Grid.Resources>

我将ComboBox的ItemsSource更改为ItemsSource =“{DynamicResource Items}”。

问题:

当我运行程序时,ComboBox会正确显示所有项目。此外,还显示带有标题的两列。它工作正常,但当我按 Enter TAB 时,焦点仍然在同一个单元格中,并且comboBox的文本显示GroupIDAndNameWithCorrespondingEffect的命名空间

以下是问题的图像:

enter image description here

示例:

如果有人想检查样本,那么它可用here。数据库文件可用here

3 个答案:

答案 0 :(得分:1)

得到了!!!!

我在Grid中使用key="Items"声明了资源。因此,当我在DataGrid的ComboBox.SelectedIndex事件中检查PreviewKeyDown时,它会给我-1,因此我的逻辑工作意外。此外,此时我得到ComboBox.Items.Count = 0

所以我刚刚改变了资源声明的地方。我的意思是我删除了Grid.Resources Section并在ComboBox.Resources section中编写了相同的代码。现在工作正常。现在在PreviewKeyDown of DataGrid,我得到了预期的SelectedIndex of the ComboBox以及ComboBox.Items.Count is equal to the Count in Source

我不知道为什么会这样?因为我已将其用作DynamicResource,所以即使它在Grid.Resources部分中声明,我也希望它能够正常工作。

答案 1 :(得分:0)

也许......也许你的组合框只需要IsEditable = false。 IsEditable = True导致组合框显示名称空间而不是文本。

答案 2 :(得分:0)

解决此问题的一种方法是http://www.shujaat.net/2010/08/wpf-editable-combobox-with-datatemplate.html

TextSearch.TextPath="GroupName"

另一种方法是向ComboBox的ItemTemplate提供DataTemplate

<ComboBox ItemTemplate="{StaticResource myDataTemplate}"/>