I'am struggling with ComboBox in my DataGrid View.
I have 2 Observable Collection. One for Data Grid where column DDV presents selected item of Combobox and second where are all options for CombBox.
Observable Collection DDV_Data (all ComboBox options) is in Observable Collection of ArtikliStoritveData.
My WPF looks like this:
<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>
And my result in DataGrid is:
It is obvious that selected item is not working. What I'am doing wrong?
I am also wondering why ComboBox in new row doesn't get bind?
DDV_Data is part of Observable Collection which is binded to DataGrid:
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())
});
DDV Property in ArtikliStoritve model:
public decimal DDV
{
get { return _ddv; }
set { _ddv = value; }
I have also noticed that when I change value in ComboBox ith changes in every row???
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
}
For ComboBox I have a class:
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; }
}
}
which i Fill in 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())
});
}
--> UPDATE
What I did. In ArtikliStoritve:
private DDV_Class _SelectedItem;
public DDV_Class SelectedItem
{
get { return _SelectedItem; }
set { _SelectedItem = value; }
}
When filling:
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())
});
}
In ArtikliStoritveModelView I also have property:
public DDV_Class SelectedItem
{
get { return ArtikliStoritve.SelectedItem; }
set { ArtikliStoritve.SelectedItem = value; OnPropertyChanged("SelectedItem"); }
}
WPF look like this:
<DataTemplate>
<ComboBox
x:Name="cmbDDV"
ItemsSource="{Binding DDV_Data}"
DisplayMemberPath="DDV"
SelectedItem="{Binding Path=SelectedItem}"
IsSynchronizedWithCurrentItem="True"
Width="50"
/>
</DataTemplate>
Result is same like picture above is showing.
--> UPDATE I figure it out why value in all rows changed when I change value in comboBox in one row. Problem vas beacuse I added in each row one istance of Observable Collection:
DDV_Data1 is not instantiate for each row, so this is a problem - one object in all rows:
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,
...
I did my testing on another column where this is now working:
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;
Now I must figure it out why is value is not getting selected in comboBox. I tested with selected value created in object where all options for comboBox is (getAll()) or in collection ArtikliStoritveData. Neither one is working.
Keep searching for right solution... :)
If I serach contect in one row, Snoop showing me this(which is right):
If do this in WPF, selected value in Combobox is first value in list, not the correct one:
<ComboBox
x:Name="cmbEM"
ItemsSource="{Binding EM_Data}"
DisplayMemberPath="Naziv"
SelectedItem="{Binding EM}"
IsSynchronizedWithCurrentItem="True"
Width="50"
/>
And finally I found a solution. Conjuction of SelectedValue and SelectedValuePath did the trick.
<ComboBox
x:Name="cmbDDV"
ItemsSource="{Binding DDV_Data}"
DisplayMemberPath="DDV"
SelectedValue="{Binding DDV, Mode=TwoWay}"
SelectedValuePath="DDV"
IsSynchronizedWithCurrentItem="True"
Width="50"
/>
On the link I found additional informations which helped me.
Regards, Igor
I think I can see where your error is... when data binding to a
ComboBox.SelectedItem
property, there are a few things to note. The first is that the object data bound to theSelectedItem
property must be of the same type as the items in the collection that is data bound to theItemsSource
property.From your code, it seems as though the collection you data bound to the
ItemsSource
property was of the type of a custom class... you didn't show that, but I guessed because you set theDisplayMemberPath
to a value ofNaziv
. So either you'd need to make yourDDV
property that you data bind to theSelectedItem
property the same type as the items in the collection , or you could try using theComboBox.SelectedValue
property in conjunction with theSelectedValuePath
property instead:UPDATE >>>
Your latest edit is not what I suggested. All the same, now that you've added the relevant code, I can see that
ArtikliStoritveData
is a collection of typeArtikliStoritve
andDDV_Data
is a property in that class which is a collection of typeDDV_Class
. Therefore, you need a property also of typeDDV_Class
in yourArtikliStoritve
class that you can bind to theSelectedIten
property:Just a couple of things to note here for the future... if you want to set the
ComboBox.SelectedItem
from the code, the item that you set as the value must be an actual item from the collection that is bound to theComboBox.ItemsSource
property. You can do it like this:Also, you should have got some errors displayed in the Output Window in Visual Studio... something like:
These are all valuable clues... pay attention to them, because they help you track down your problems.
I added solution at the end of the question.
Regards, Igor