如何在WPF中的数据网格内处理组合框? [英] How do I work on combobox inside a datagrid in WPF?

查看:71
本文介绍了如何在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 for INotifyPropertyChanged 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆