【问题标题】:Bind selected value of a multicolumn combobox inside DataGrid绑定 DataGrid 内多列组合框的选定值
【发布时间】:2014-09-13 20:17:55
【问题描述】:

工作示例:

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

看了上面的图片,我想你可能已经明白主键和外键存在于同一个表中。我认为这就是开发人员所说的循环引用。

在 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, 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 //转换器

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 中使用多列组合框而不是简单的组合框。

我有两张桌子:

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

我添加了一个名为 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>

网格资源内部:

    <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 正确显示所有项目。此外,还会显示带有标题的两列。它工作正常,但是当我按 EnterTAB 时,焦点仍然在同一个单元格中,并且组合框的文本显示 GroupIDAndNameWithCorrespondingEffect 的命名空间

这是问题的图像:

示例:

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

【问题讨论】:

  • 由于此处没有 SQL 服务器,我无法运行提供的示例。您能否提供一个不依赖于 SQL 等的静态数据示例?
  • 我不知道如何在我的代码中创建这些关系,所以我使用 ef 从数据库中获取这些关系。所以,我的数据来自数据库而不是静态数据源。我已经在这里上传了我的数据库文件:drive.google.com/file/d/0B5WyqSALui0bQzdWOWc4Q2tvY1E/…
  • @pushpraj 你现在可以运行这个项目了吗?
  • 还没有,我需要先安装sql server,我稍后再试试。
  • @pushpraj 谢谢。如果您在运行项目中发现任何问题,请告诉我。

标签: c# wpf xaml datagrid combobox


【解决方案1】:

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

【讨论】:

  • 但我需要组合框的 IsEditable 行为为真。
  • 如果你需要 IsEditable = True 那么也许将要显示的文本放在带有 Textsearch.Text 的组合框标签内可能会这样做: .这必须与组合框“内部”的文本完全相同。
  • 我 100% 确定我的绑定需要更改。但我不知道要绑定的模型的正确属性。
  • 不能是同一个文本。它可以是任何文本,我发现它会显示出来。
  • 对不起...我无法理解您的上述评论。
【解决方案2】:

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

TextSearch.TextPath="GroupName"

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

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

【讨论】:

  • 感谢您的建议。但我已经使用过 TextSearch.TextPath。看看我的示例项目
  • 你试过ItemTemplate了吗?
  • 感谢您帮助我。经过几天的努力,我得到了答案。有关我是如何解决的,请参阅我的答案。
【解决方案3】:

知道了!!!!

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

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

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

【讨论】:

  • @pushpraj 谢谢。你能回答我回答中的问题吗?现在 datagrid 给了我预期的行为,但为什么它在 Grid.Resources 部分不起作用?
  • 在我看来,当单元格通过某些步骤进入编辑模式时,它看起来像是模板解析策略的问题。为避免此类问题,请选择 StaticResource 而不是 DynamicResource,如果无法解决则会失败,因此您可能看不到类的全名而不是预期的输出。
  • @pushpraj 感谢您的建议。我会记住的。
猜你喜欢
  • 2018-01-17
  • 2018-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多