winforms 如何绑定动态创建的文本框?

yrwegjxp  于 2022-12-23  发布在  其他
关注(0)|答案(2)|浏览(199)

我正在尝试为hotel创建pricelist。我有一个日期列表和hotel中的房间类型列表。该列表可以包含随机数量的元素。这是动态创建的,代码如下:

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;
    }`

以下是该表示的图像。

现在我面临着一个数据绑定的问题。我需要为每个文本框双向绑定价格。我被卡住了。
我尝试将其绑定到属性名称,但所有框都获得相同的值。如果尝试通过索引将其绑定到值,则会收到错误Cannot bind to the property or column 34 on the DataSource. Parameter name: dataMember
下面的代码用于填充演示者中使用的模型

` 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);
        }
    }`

最后是用作模型的类。

` 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");
          }

    }
}`

有人有什么建议吗?

3z6pesqy

3z6pesqy1#

创建用于存储文本框的列表:

List<TextBox> lstTextbox = new List<TextBox>();

创建存储“日期”和“房间类型”值的类对象

public class RoomTypeDate
{
    public string RoomType = "";
    public string DateRange = "";
}

创建文本框后,立即将RoomTypeDate信息分配给标记,并将其添加到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++;                    
}

现在,获取并设置房价:

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;
}
  • 代码未经测试,可能包含错误
whlutmcx

whlutmcx2#

你的问题是:* * 如何绑定动态创建的文本框**.这里有一个tested方法来完成这个特定的任务。
首先动态创建一些文本框:

public MainForm()
{
    InitializeComponent();
    buttonRandom.Click += (sender, e) => generateRandomList();
}
protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    List<TextBox> tmp = new List<TextBox>();
    for (int column = 1; column < tableLayoutPanel.ColumnCount; column++)
    {
        for (int row = 1; row < tableLayoutPanel.RowCount; row++)
        {
            TextBox textBox = new TextBox { Anchor = (AnchorStyles)0xF };
            tableLayoutPanel.Controls.Add(textBox, column, row);
            tmp.Add(textBox);
            textBox.KeyDown += onAnyTextBoxKeyDown;
        }
    }
    _textboxes = tmp.ToArray();
    // Generate first dataset
    generateRandomList();
}
TextBox[] _textboxes = null;

然后,每当生成新的随机列表时,在为每个TextBox创建新的数据绑定之前,清除其中的所有旧文本和数据绑定。

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
    }
}

代码中显示为绑定源的类可能无法正确绑定。我注意到的一个问题是,属性设置器无法在触发通知之前检查值 * 是否实际更改了 *。下面是一个正确执行此操作的示例。(出于测试目的,我显示了一个实现INotifyPropertyChanged的类的Minimal Reproducible Sample "模拟"版本。)

enum Sobe { APP4 = 1, APP5, STUDIO, SUP, APP6, STAND, STDNT, COMSTU, LUXSTU, APP4C, APP4L, APP62, APP6L }
class VrstaSobeCena : INotifyPropertyChanged
{
    decimal _price = 100 + (50 * (decimal)Rando.NextDouble());
    public decimal Cena
    {
        get => _price;
        set
        {
            if (!Equals(_price, value))
            {
                _price = value;
                OnPropertyChanged();
            }
        }
    }
    Sobe _sobe = 0;
    public Sobe Sobe
    {
        get => _sobe;
        set
        {
            if (!Equals(_sobe, value))
            {
                _sobe = value;
                OnPropertyChanged();
            }
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

最后,测试双向绑定的一种方法是拦截[Enter]键。

private void onAnyTextBoxKeyDown(object sender, KeyEventArgs e)
{
    if ((e.KeyCode == Keys.Enter) && (sender is TextBox textbox))
    {
        e.SuppressKeyPress = e.Handled = true;
        VrstaSobeCena vrstaSobeCena = (VrstaSobeCena)textbox.Tag;
        string msg = $"Price for {vrstaSobeCena.Sobe} is {vrstaSobeCena.Cena.ToString("F2")}";
        BeginInvoke((MethodInvoker)delegate {MessageBox.Show(msg); });
        SelectNextControl(textbox, forward: true, tabStopOnly: true, nested: false, wrap: true);
    }
}

相关问题