如何将控件绑定到运行时动态添加的属性?

问题描述 投票:0回答:1

我看到各种关于如何将属性绑定到静态控件的教程,即txt_box1.Text绑定到Prop1,txt_box2.Text绑定到Prop2,等等。 但如您所知,文本框或绑定到属性的任何其他控件在程序启动时都在那里。绑定已在 XAML 中。

但是,我的问题是,在提供用户输入之前,我不知道需要多少个绑定。这意味着我将在运行时添加控件以及应绑定到它们的属性。因此,一旦将控件添加到面板中,我就失去了通过名称引用它的能力......至少在我对 C#/WPF 的有限知识中是这样。

早在 Borland Delphi/C++ Builder 时代,我滥用了对象的“Tag”属性,为其分配循环索引值并跟踪动态添加到数组中的各个对象。也许有更聪明的方法来做到这一点,但我不知道更好,至少它解决了问题。但我在这里不使用它,所以我不限制你的建议。

请参阅下面的 XAML 和 C#。

<Window x:Class="SO_Binding.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:SO_Binding"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="600">
    <StackPanel>
        <WrapPanel>
            <Label Content="How many textboxes?"></Label>
            <TextBox x:Name="txt_numboxes" Width="50" KeyDown="txt_numboxes_KeyDown"></TextBox>
        </WrapPanel>
        <Separator></Separator>

        <StackPanel x:Name="spanel">
            
        </StackPanel>
    </StackPanel>
</Window>

C#

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace SO_Binding
{
    public partial class MainWindow : Window
    {
        List<String> ourlist = new List<String>();

        public MainWindow()
        {
            InitializeComponent();
        }

        private void txt_numboxes_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                ourlist?.Clear();
                ourlist.Capacity = Convert.ToInt32(txt_numboxes.Text);
                ourlist.Add("");                            // Initialize the list with empty strings

                spanel.Children?.Clear();
                for(int i = 0; i < Convert.ToInt32(txt_numboxes.Text); i++)
                    spanel.Children.Add(new TextBox());     // Each of these textboxes should be bound to their respective strings in the list

                spanel.Children.Add(new Separator());

                for (int i = 0; i < Convert.ToInt32(txt_numboxes.Text); i++)
                    spanel.Children.Add(new TextBlock());   // Display the strings in their respective textblocks to check the binding
            }
        }
    }
}

输入像 5 这样的数字并按 Enter 键后,它会创建 5 个文本框和文本块,将列表容量增加到 5 并对其进行初始化。 Textbox 0 和 Textblock 0 应绑定到 List[0],以便当您键入内容时,属性会更新并且文本块会显示它。 我不知道在事前未知的情况下该怎么做,或者即使有可能。如果你知道请告诉我。

c# wpf
1个回答
0
投票

看这个例子:

using Simplified;
using System.Collections.ObjectModel;

namespace Core2024.SO.JayY
{
    public class ChangingCountTextBoxesVM : ViewModelBase
    {
        public int Count { get => Get<int>(); set => Set(value); }

        public ReadOnlyObservableCollection<TextField> Fields { get; }
        private readonly ObservableCollection<TextField> FieldsList = new();

        public ChangingCountTextBoxesVM()
        {
            Fields = new(FieldsList);
            Count = 3;
        }

        protected override void OnPropertyChanged(string propertyName, object oldValue, object newValue)
        {
            base.OnPropertyChanged(propertyName, oldValue, newValue);

            if (propertyName == nameof(Count))
            {
                int count = (int)newValue;
                FieldsList.Clear();
                for (int i = 0; i < count; i++)
                {
                    FieldsList.Add(new TextField());
                }
            }
        }
    }

    public class TextField : ViewModelBase
    {
        public string Text { get => Get<string>(); set => Set(value); }
    }
}
<Window x:Class="Core2024.SO.JayY.ChangingCountTextBoxesWindow"
        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:Core2024.SO.JayY"
        mc:Ignorable="d"
        Title="ChangingCountTextBoxesWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:ChangingCountTextBoxesVM/>
    </Window.DataContext>
    <StackPanel>
        <WrapPanel>
            <Label Content="How many textboxes?"></Label>
            <TextBox x:Name="txt_numboxes" Width="50" Text="{Binding Count, UpdateSourceTrigger=PropertyChanged}"></TextBox>
        </WrapPanel>
        <Separator></Separator>

        <StackPanel x:Name="spanel">
            <ItemsControl ItemsSource="{Binding Fields}" >
                <ItemsControl.ItemTemplate>
                    <DataTemplate DataType="{x:Type local:TextField}">
                        <TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}"/>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        <Separator></Separator>
            <ItemsControl ItemsSource="{Binding Fields}" >
                <ItemsControl.ItemTemplate>
                    <DataTemplate DataType="{x:Type local:TextField}">
                        <TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}"
                                 IsReadOnly="True"/>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </StackPanel>
    </StackPanel>
</Window>
© www.soinside.com 2019 - 2024. All rights reserved.