我看到各种关于如何将属性绑定到静态控件的教程,即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],以便当您键入内容时,属性会更新并且文本块会显示它。 我不知道在事前未知的情况下该怎么做,或者即使有可能。如果你知道请告诉我。
看这个例子:
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>