【问题标题】:WPF selected value in ComboBox组合框中的 WPF 选定值
【发布时间】:2014-03-23 13:18:51
【问题描述】:

我在 DataGrid 视图中遇到了 ComboBox。

我有 2 个可观察的集合。一个用于数据网格,其中列 DDV 显示 Combobox 的选定项,第二个是 CombBox 的所有选项。

Observable Collection DDV_Data(所有 ComboBox 选项)位于 ArtikliStoritveData 的 Observable Collection 中。

我的 WPF 如下所示:

        <DataGrid ItemsSource="{Binding Path=ArtikliStoritveData}" AutoGenerateColumns="False" SelectionMode="Single" CanUserAddRows="True" x:Name="dgArtikliStoritve" HorizontalAlignment="Left" Margin="31,58,0,0" VerticalAlignment="Top" Height="229" Width="612">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Šifra" Binding="{Binding Sifra}" />
            <DataGridTextColumn Header="Naziv" Binding="{Binding Naziv}" Width="200"/>
            <DataGridTextColumn Header="Znesek" Binding="{local:CultureAwareBinding Path=Znesek, StringFormat={}{0:C}}"/>
            <DataGridTextColumn Header="DDV" Binding="{local:CultureAwareBinding Path=DDV}" />
            <DataGridTextColumn Header="EM" Binding="{Binding EM}" />
            <DataGridTextColumn Header="Datum spremembe" Binding="{local:CultureAwareBinding Path=DatumSpremembe}" />
            <DataGridTemplateColumn Header="DDV">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <ComboBox
                            x:Name="cmbDDV"
                            ItemsSource="{Binding DDV_Data}"
                            SelectedValuePath="DDV"
                            DisplayMemberPath="DDV"
                            SelectedValue="{Binding DDV1}"
                            IsSynchronizedWithCurrentItem="True"
                            Width="50"
                        />
                        </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTextColumn Binding="{Binding Artikel_ID}" Width="0" Visibility="Hidden"/>
            <DataGridTextColumn Binding="{Binding SkupinaArtikla}" Width="0" Visibility="Hidden"/>
        </DataGrid.Columns>
    </DataGrid>

我在 DataGrid 中的结果是:

很明显,所选项目不起作用。我做错了什么?

我也想知道为什么新行中的 ComboBox 没有绑定?

DDV_Data 是绑定到 DataGrid 的 Observable Collection 的一部分:

                ArtikliStoritveData.Add(new ArtikliStoritve
                {    
                    Artikel_ID = Convert.ToInt32(dt.Rows[i]["artikel_id"].ToString()),
                    SkupinaArtikla = Convert.ToInt32(dt.Rows[i]["skupina_artikla"].ToString()),
                    Sifra = dt.Rows[i]["sifra"].ToString(),
                    EM = dt.Rows[i]["em"].ToString(),
                    Naziv = dt.Rows[i]["naziv"].ToString(),
                    DDV = Convert.ToDecimal(dt.Rows[i]["ddv"].ToString()),
                    DDV_Data = DDV_Data1,
                    SelectedItem = "22.0",
                    Znesek = Decimal.Parse(dt.Rows[i]["znesek"].ToString()) ,
                    DatumSpremembe = DateTime.Parse(dt.Rows[i]["date_changed"].ToString())
                });    

ArtikliStoritve 模型中的 DDV 属性:

    public decimal DDV
    {
        get { return _ddv; }
        set { _ddv = value; }

我还注意到,当我更改 ComboBox 中的值时,每一行都会发生变化???

ArtikliStoritve:

class ArtikliStoritve
{

    #region private varaibles
    int _artikel_id;
    int _skupinaArtikla;
    string _sifra;
    string _naziv;
    string _EM;
    decimal _ddv;
    decimal _znesek;
    DateTime _datum_spremembe;

    #endregion

    #region properties
    public int Artikel_ID
    {
        get { return _artikel_id; }
        set { _artikel_id = value; }
    }

    public int SkupinaArtikla
    {
        get { return _skupinaArtikla; }
        set { _skupinaArtikla = value; }
    }

    public string Sifra
    {
        get { return _sifra; }
        set { _sifra = value; }
    }

    public string EM
    {
        get { return _EM; }
        set { _EM = value; }
    }

    public string Naziv
    {
        get { return _naziv; }
        set { _naziv = value; }
    }

    public decimal DDV1
    {
        get { return _ddv; }
        set { _ddv = value; }
    }

    public decimal Znesek
    {
        get { return _znesek;}
        set { _znesek = value; }
    }

    public DateTime DatumSpremembe
    {
        get { return _datum_spremembe; }
        set { _datum_spremembe = value; }
    }

    private decimal _SelectedItem;
    public decimal SelectedItem
    {
        get { return _SelectedItem; }
        set { _SelectedItem = value; }
    }

    private ObservableCollection<DDV_Class> _DDV_Data = new ObservableCollection<DDV_Class>();
    public ObservableCollection<DDV_Class> DDV_Data
    {
        get { return _DDV_Data; }
        set { _DDV_Data = value; }
    }
    #endregion
}

对于 ComboBox,我有一个类:

class DDV_Class
{
    private int _ID;
    public int ID
    {
        get { return _ID; }
        set { _ID = value; }
    }

    private decimal _DDV;
    public decimal DDV
    {
        get { return _DDV; }
        set { _DDV = value; }
    }
}

我在 ArtikliStoritveViewModel 中填写的内容:

for (int i = 0; i < dtDDV.Rows.Count; i++)
{
    DDV_Data1.Add(new DDV_Class
    {
        ID = Convert.ToInt32(dtDDV.Rows[i]["ID"].ToString()),
        DDV = Convert.ToDecimal(dtDDV.Rows[i]["DDV"].ToString())
    });
}

--> 更新

我做了什么。在 ArtikliStoritve 中:

private DDV_Class _SelectedItem;
public DDV_Class SelectedItem
{
    get { return _SelectedItem; }
    set { _SelectedItem = value; }
}

填充时:

for (int i = 0; i < dt.Rows.Count; ++i)
{
    ArtikliStoritveData.Add(new ArtikliStoritve
    {
        Artikel_ID = Convert.ToInt32(dt.Rows[i]["artikel_id"].ToString()),
        SkupinaArtikla = Convert.ToInt32(dt.Rows[i]["skupina_artikla"].ToString()),
        Sifra = dt.Rows[i]["sifra"].ToString(),
        EM = dt.Rows[i]["em"].ToString(),
        Naziv = dt.Rows[i]["naziv"].ToString(),
        DDV1 = Convert.ToDecimal(dt.Rows[i]["ddv"].ToString()),
        DDV_Data = DDV_Data1,
        SelectedItem = new DDV_Class { ID = 1, DDV = 22.0m },
        Znesek = Decimal.Parse(dt.Rows[i]["znesek"].ToString()),
        DatumSpremembe = DateTime.Parse(dt.Rows[i]["date_changed"].ToString())
    });        
}

在 ArtikliStoritveModelView 我也有财产:

public DDV_Class SelectedItem
{
    get { return ArtikliStoritve.SelectedItem; }
    set { ArtikliStoritve.SelectedItem = value; OnPropertyChanged("SelectedItem"); }
}

WPF 看起来像这样:

<DataTemplate>
    <ComboBox
        x:Name="cmbDDV"
        ItemsSource="{Binding DDV_Data}"
        DisplayMemberPath="DDV"
        SelectedItem="{Binding Path=SelectedItem}"
        IsSynchronizedWithCurrentItem="True"
        Width="50"
    />
</DataTemplate>

结果如上图所示。

--> 更新 我弄清楚为什么当我在一行中更改组合框中的值时所有行中的值都发生了变化。问题是因为我在每一行中添加了一个 Observable Collection:

DDV_Data1 不是为每一行实例化,所以这是一个问题 - 所有行中的一个对象:

DataTable dtDDV = myDDV_DAL.getAll();
if (dtDDV.Rows.Count > 0)
{
    for (int i = 0; i < dtDDV.Rows.Count; i++)
    {
        DDV_Data1.Add(new DDV_Class
        {
            ID = Convert.ToInt32(dtDDV.Rows[i]["ID"].ToString()),
            DDV = Convert.ToDecimal(dtDDV.Rows[i]["DDV"].ToString())
        });
    }
}

ArtikliStoritveDAL myArtikliStoritveDAL  = new ArtikliStoritveDAL();
DataTable dt = myArtikliStoritveDAL.getAll();
if (dt.Rows.Count > 0)
{
    for (int i = 0; i < dt.Rows.Count; ++i)
    {
        ArtikliStoritveData.Add(new ArtikliStoritve
        {
            ...
            DDV_Data = DDV_Data1,
            ...

我在另一个列上进行了测试,现在它正在工作:

EM_DAL myEM_DAL = new EM_DAL();
DataTable dtEM = myEM_DAL.getAll();
if (dtEM.Rows.Count > 0)
{
    for (int i = 0; i < dtEM.Rows.Count; i++)
    {
        EM_Data.Add(new EM_Model
        {
            ID = dtEM.Rows[i]["EM"].ToString(),
            Naziv = dtEM.Rows[i]["EM"].ToString()
        });
    }
}

    ArtikliStoritveDAL myArtikliStoritveDAL  = new ArtikliStoritveDAL();
DataTable dt = myArtikliStoritveDAL.getAll();
if (dt.Rows.Count > 0)
{
    for (int i = 0; i < dt.Rows.Count; ++i)
    {
        ArtikliStoritveData.Add(new ArtikliStoritve
        {
            ...
            EM_Data = getAll(dt.Rows[i]["em"].ToString()),
            ...


public List<EM_Model> getAll(string p_selected)
{
    List<EM_Model> myEM_Model = new List<EM_Model>();
    string strConnString = Util.getConnectionString();
    try
    {
        NpgsqlConnection conn = new NpgsqlConnection(strConnString);
        DataTable dt = new DataTable();
        conn.Open();
        NpgsqlDataAdapter da = new NpgsqlDataAdapter("SELECT em, em "
                                                        + " FROM em", conn);
        da.Fill(dt);
        conn.Close();
        for (int i = 0; i < dt.Rows.Count; i++)
        {
            myEM_Model.Add(new EM_Model
            {
                ID = dt.Rows[i]["EM"].ToString(),
                Naziv = dt.Rows[i]["EM"].ToString(),
                SelectedItem1 = p_selected
            });
        }
        return myEM_Model;

现在我必须弄清楚为什么没有在组合框中选择值。我测试了在组合框的所有选项为 (getAll()) 的对象或 ArtikliStoritveData 集合中创建的选定值。一个都没有工作。

继续寻找正确的解决方案... :)

如果我连续搜索,Snoop 会向我展示这个(这是正确的):

如果在 WPF 中执行此操作,则 Combobox 中的选定值是列表中的第一个值,而不是正确的值:

<ComboBox
    x:Name="cmbEM"
    ItemsSource="{Binding EM_Data}"
    DisplayMemberPath="Naziv"
    SelectedItem="{Binding EM}"
    IsSynchronizedWithCurrentItem="True"
    Width="50"
/>

最后我找到了解决方案。 SelectedValue 和 SelectedValuePath 的结合起到了作用。

<ComboBox
    x:Name="cmbDDV"
    ItemsSource="{Binding DDV_Data}"
    DisplayMemberPath="DDV"
    SelectedValue="{Binding DDV, Mode=TwoWay}" 
    SelectedValuePath="DDV" 
    IsSynchronizedWithCurrentItem="True"
    Width="50"
/>

link 上,我发现了对我有帮助的其他信息。

问候, 伊戈尔

【问题讨论】:

  • 看起来DDV_Data 不是绑定到网格行的数据项的属性。如果您查看 Visual Studio 中的输出窗口,您会看到绑定错误。
  • 我在输出窗口中没有任何错误。我发布了一个代码,证明 DDV_Data 是 ArtikliStoritveData 集合的一部分。
  • DataGrid 第二行的选定值必须是 22,0,就像第一列 DDV 一样
  • 显示您的 DVV 资产。显示 ArtikliStoritve
  • 显示 ArtikliStoritve 和 _ddv

标签: c# wpf mvvm datagrid combobox


【解决方案1】:

我在问题的末尾添加了解决方案。

问候, 伊戈尔

【讨论】:

    【解决方案2】:

    我想我可以看到您的错误在哪里......当数据绑定到ComboBox.SelectedItem 属性时,有几件事需要注意。首先是绑定到SelectedItem 属性的对象数据必须是与绑定到ItemsSource 属性的数据集合中的项目相同的类型

    从您的代码看来,您的数据绑定到 ItemsSource 属性的集合似乎属于自定义类的类型...您没有显示,但我猜是因为您设置了 DisplayMemberPath值为Naziv。因此,要么您需要将数据绑定到 SelectedItem 属性的 DDV 属性与集合中的项目类型相同,或者您可以尝试将 ComboBox.SelectedValue 属性与 SelectedValuePath 结合使用改为属性:

    <ComboBox x:Name="cmbDDV" 
        ItemsSource="{Binding Path=DDV_Data}"
        DisplayMemberPath="Naziv"
        SelectedValuePath="Naziv"
        IsSynchronizedWithCurrentItem="True"
        SelectedValue="{Binding Path=DDV}"
        Width="50" />
    

    更新>>>

    您的最新编辑不是我所建议的。同样,既然您已经添加了相关代码,我可以看到ArtikliStoritveDataArtikliStoritve 类型的集合,DDV_Data 是该类中的一个属性,它是一个集合DDV_Class 类型。因此,您还需要 ArtikliStoritve 类中的 DDV_Class 类型的属性,您可以将其绑定到 SelectedIten 属性:

    <ComboBox x:Name="cmbDDV" 
        ItemsSource="{Binding Path=DDV_Data}"
        SelectedItem="{Binding Path=SelectedItem}"
        IsSynchronizedWithCurrentItem="True"
        Width="50" />
    
    ...
    
    private DDV_Class _SelectedItem;
    public DDV_Class SelectedItem
    {
        get { return _SelectedItem; }
        set { _SelectedItem = value; }
    }
    
    private ObservableCollection<DDV_Class> _DDV_Data = new ObservableCollection<DDV_Class>();
    public ObservableCollection<DDV_Class> DDV_Data
    {
        get { return _DDV_Data; }
        set { _DDV_Data = value; }
    }
    

    这里只需要注意几件事以备将来使用...如果您想从代码中设置ComboBox.SelectedItem,您设置为值的项目必须是集合中的实际项目 绑定到 ComboBox.ItemsSource 属性。你可以这样做:

    SelectedItem = DDV_Data.Where(d => d.ID == someIdValue).Single();
    

    此外,您应该在 Visual Studio 的输出窗口中显示一些错误...类似于:

    System.Windows.Data 错误:40:BindingExpression 路径错误:在“对象”“NameOfDataBoundObject”(名称=“”)上找不到“某些”属性。 BindingExpression:Path=SomePath; DataItem='NameOfDataBoundObject' (Name='');目标元素是 'TypeOfUiElement' (Name='NameOfUiElement');目标属性是“PropertyName”(类型“TypeOfProperty”)

    这些都是有价值的线索...注意它们,因为它们可以帮助您找到问题。

    【讨论】:

    • 在输出窗口中我得到这个:ystem.Windows.Data 错误:7:ConvertBack 无法转换值“Risa.Model.DDV_Class”(类型“DDV_Class”)。绑定表达式:路径=选定项; DataItem='ArtikliStoritve' (HashCode=34092959);目标元素是'ComboBox'(名称='cmbDDV');目标属性是'SelectedItem'(类型'Object') NotSupportedException:'System.NotSupportedException: DecimalConverter cannot convert from Risa.Model.DDV_Class.
    • 您是否像发布的答案一样删除了 SelectdItem?
    猜你喜欢
    • 2013-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多