I'm trying to create pricelist for hotel. I'm having a list of dates, and list of room types in hotel. That lists can contain random number of elements. That is created dynamically, and here is the code:
private void CreateControls() { var colIndex = 0;
var vrsteSoba = _Presenter.VrstaSobeDto.ToArray();
foreach (var bindingItem in vrsteSoba)
{
var lbl = new Label()
{
Width = LABEL_WIDTH,
Height = LABEL_HEIGHT - 5,
Left = 10,
Top = 30 colIndex * (EDIT_BOX_HEIGHT SPACE_BETWEEN_CONTROL),
Text = bindingItem
};
_dataPanel.Controls.Add(lbl);
colIndex ;
}
int a = 1;
foreach (var date in _Presenter.CeneTarifa)
{
int y = 0;
var panel = new Panel
{
Height = PANEL_HEIGHT * (vrsteSoba.Length-4),
Width = EDIT_BOX_WIDTH,
Left = a * (EDIT_BOX_WIDTH SPACE_BETWEEN_CONTROL 50),
Top = 5
};
_dataPanel.Controls.Add(panel);
var label = new Label
{
Height = EDIT_BOX_HEIGHT,
Location = new Point(0, 10),
Text = date.Datum,
Margin = new Padding(0)
};
panel.Controls.Add(label);
int index = 0;
foreach (var item in date.VrstaSobeCena)
{
var box = new TextBox();
panel.Controls.Add(box);
box.Height = EDIT_BOX_HEIGHT;
box.Width = EDIT_BOX_WIDTH;
box.Location = new Point(0, 30 y * (EDIT_BOX_HEIGHT SPACE_BETWEEN_CONTROL));
box.DataBindings.Add(new Binding(nameof(box.Text), date, date.Cena[index].Cena1));
y ;
index ;
}
a;
}
_dataPanel.AutoScroll = true;
}`
Here is image of that representation.
Now I'm facing a problem of data binding. I need to bind price, two way, for each text box. And I'm stuck.
I have tried to bind it to property name, but then all boxes get same value. If I try to bind it to value via index, I'm getting error
Cannot bind to the property or column 34 on the DataSource. Parameter name: dataMember
Code below is used to fill model that is used in presenter
` private void FillCenePoTarifi() { var sobeArr = VrstaSobeDto.ToArray();
foreach (var datum in Datumi)
{
var dictionary = new Dictionary<string, decimal>();
var cene = new List<Cena>();
foreach (var item in sobeArr)
{
var tarif = _Tarife.Where(x => x.SifTarife == item).FirstOrDefault();
if (tarif != null)
_SastavTarife = HotelierServerLocal.Default.TarifaViewBlo.GetSastaveTarife(tarif.IdTarife);
//proveriti ovu logiku
var cena = _SastavTarife.Where(x => x.Cena1 != 0).Select(c => c.Cena1).FirstOrDefault();
cene.Add(new Cena { Cena1 = cena.ToString()});
dictionary.Add(item, cena);
}
var model = new CenePoTarifi
{
Datum = datum,
VrstaSobeCena = dictionary,
Cena = cene
};
CeneTarifa.Add(model);
}
}`
Finally here are classes that use as model.
` public class CenePoTarifi{
public Dictionary<string, decimal> VrstaSobeCena { get; set; } = new Dictionary<string, decimal>();
public string Datum { get; set; }
private List<Cena> _Cena;
public List<Cena> Cena
{
get => _Cena;
set
{
_Cena = value;
NotifyPropertyChanged("Cena");
}
}
public class Cena :
{
private string _Cena1;
public string Cena1
{
get => _Cena1;
set
{
_Cena = value;
NotifyPropertyChanged("Cena1");
}
}
}`
Does anyone has any suggestions?
CodePudding user response:
Create a List for storing the textbox:
List<TextBox> lstTextbox = new List<TextBox>();
Create a class object that stores the values of "Date" and "room type"
public class RoomTypeDate
{
public string RoomType = "";
public string DateRange = "";
}
Immediately after you created the textbox, assigned the RoomTypeDate
info to the tag, add it to lstTextbox
.
foreach (var item in date.VrstaSobeCena)
{
var box = new TextBox();
panel.Controls.Add(box);
box.Height = EDIT_BOX_HEIGHT;
box.Width = EDIT_BOX_WIDTH;
box.Location = new Point(0, 30 y * (EDIT_BOX_HEIGHT SPACE_BETWEEN_CONTROL));
box.DataBindings.Add(new Binding(nameof(box.Text), date, date.Cena[index].Cena1));
// add the box to the list
lstTextbox.Add(box);
// mark the box with RoomType and DateRange
RoomTypeDate rtd = new RoomTypeDate();
rtd.RoomType = "APP4"; // get the room type
rtd.DateRange = "1.6 - 30.6"; // get date range
box.Tag = rtd;
y ;
index ;
}
Now, to get and set the room price:
public void SetRoomPrice(decimal price, string roomType, string dateRange)
{
foreach (var tb in lstTextBox)
{
var rtd = (RoomTypeDate)tb.Tag;
if(rtd.RoomType == roomType && rtd.DateRange == dateRange)
{
tb.Text = price.ToString();
return;
}
}
}
public decimal GetRoomPrice(string roomType, string dateRange)
{
foreach (var tb in lstTextBox)
{
var rtd = (RoomTypeDate)tb.Tag;
if(rtd.RoomType == roomType && rtd.DateRange == dateRange)
{
return Convert.ToDecimal(rt.Text);
}
}
return 0m;
}
*code untested, might contains bugs
CodePudding user response:
Your question is: How to bind dynamically created text box. Here is one
Then, whenever a new random list is generated, clear any old text and databindings from every TextBox
before creating a new data binding for it.
public static Random Rando { get; } = new Random(2);
private void generateRandomList()
{
// Clear ALL the data bindings for ALL the textboxes.
foreach (var textbox in _textboxes)
{
textbox.Clear();
textbox.DataBindings.Clear();
}
// Generate and create new bindings
int count = Rando.Next(1, 79);
for (int i = 0; i < count; i )
{
var textbox = _textboxes[i];
VrstaSobeCena vrstaSobeCena =
new VrstaSobeCena{ Sobe = (Sobe)tableLayoutPanel.GetRow(textbox) };
textbox.Tag = vrstaSobeCena;
textbox.DataBindings.Add(
new Binding(
nameof(TextBox.Text),
vrstaSobeCena,
nameof(VrstaSobeCena.Cena),
formattingEnabled: true,
dataSourceUpdateMode: DataSourceUpdateMode.OnPropertyChanged,
null,
"F2"
));
// TO DO
// ADD vrstaSobeCena HERE to the Dictionary<string, decimal> VrstaSobeCena
}
}
One issue I noticed in the code you posted is that it fails to check whether the value has actually changed before firing the notification. This mock class shows one way to do that correctly. (For testing purposes I'm showing a