0

我对 C# 很陌生,并且遇到了以下问题:我的程序在运行时创建了一个对象字典(大小未知),数据不足。对于每个对象,我想创建一个 StackPanel 元素,里面有两个 TextBox,我这样做如下:

foreach (string name in a.Keys){
    StackPanel SP = new StackPanel();
    TextBox TB1 = new TextBox();
    TextBox TB2 = new TextBox();
    SP.Children.Add(TB1);
    SP.Children.Add(TB2);
    // ... Content to TextBoxes 
    TB2.Name = name;
}

现在,我在程序的其他地方放置了一个复选框,如果上面每个 StackPanel 中的第二个文本框可见,它应该切换,例如,通过以下方式:

void MainCheckBox_Clicked(object sender, RoutedEventArgs e){
    if (MainCheckBox.IsChecked == true){XXX.Height = 300;}
    else {XXX.Height = 0;}
}

这里的 XXX 应该是对名为“TB2”的 TextBox 的引用。但是使用列表中的任何“名称”(应该对应于 TB2 的名称)都不起作用,编译器会说“名称”不存在,即使我从字面上使用列表中的具体名称,例如 ' John'(假设他在列表中)。

我假设我在概念上做错了什么,那么根据数据创建这些东西的更好方法是什么?

提前致谢!

4

6 回答 6

3

您将需要保留对TextBox您创建的对象的引用。例如,您可以创建一个Dictionary<string, TextBox>来存储引用:

private Dictionary<string, TextBox> myTextBoxes = new Dictionary<string, TextBox>();

创建TextBox对象时,您会将它们添加到字典中:

myTextBoxes.Add(name, TB2);

然后你会TextBox像这样访问你的:

myTextBoxes["TextBoxName"].Height = 300;
于 2012-07-19T12:26:59.133 回答
1

一种简单的方法是遍历所有控件,然后检查类型和名称(或您提供给控件的标签)。然后你可以正常处理控制。对于迭代,我将使用以下内容:

    foreach(TextBox tb in this.Controls.OfType<TextBox>().Where(t => t.Name.Equals("SEARCHEDNAME")))
        {
            //Do something with the control and then u can break
        }
于 2012-07-19T12:26:47.687 回答
1

您可以搜索 WPF 的 VisualTree 以查找具有您的名字的对象(我VisualTreeHelpers的博客上有一些您可能会觉得有用,它们显示了一些 Visual Tree Navigation 示例)

var tb = VisualTreeHelpers.FindChild<TextBox>(this, tbName);
if (tb != null)
    tb.Height = (MainCheckBox.IsChecked ? 300 : 0);

或者您可以利用 WPF 的绑定系统为您执行此操作。如果您在代码隐藏中制作控件,我个人会使用 Style

<Style x:Key="SecondTextBoxStyle" TargetType="{x:Type TextBox}">
    <Setter Property="Height" Value="0" />
    <Style.Triggers>
        <DataTrigger Binding="{Binding ElementName=MainCheckBox, Path=IsChecked}" Value="True">
            <Setter Property="Height" Value="300" />
        </DataTrigger>
    </Style.Triggers>
</Style>

然后当你创建你的文本框时:

TB2.Style = this.FindResource("SecondTextBoxStyle") as Style;

在理想的世界中,我什至不会使用代码隐藏来制作对象。相反,我会使用ItemsControl绑定到您的KeysObservableCollection,并将其设置ItemTemplate为您想要的任何内容。

<ItemsControl ItemsSource="{Binding Keys}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBox ... />
                <TextBox Style="{StaticResource SecondTextBoxStyle}" ... />
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>
于 2012-07-19T12:39:49.200 回答
1

简单的方法是获取动态创建的对象 - 将它们放入集合中 - 创建数据模板,以便 wpf 知道如何呈现 - 并将这些集合放入 itemscontrol。有些人首先用 viewmodel 调用这个 mvvm ;)

你的动态对象包装器

public class MyObject //should implement INotifyPropertyChanged
{ 
  //your public properties goes here
}

您的视图模型,它处理集合和检索集合的数据

public class MyViewmodelWithDynamicCollection //should implement INotifyPropertyChanged
{
   public ObservableCollection<MyObject> MyItems {get;set;}//just init once and add, remove, clear like you want

}

在你看来资源

<DataTemplate DataType="{x:Type local:MyObject}">
    <StackPanel>
        <TextBlock Text="{Binding MyReadonlyProperty}"/>
        <TextBox Text="{Binding MyEditableProperty}"/>
    </StackPanel>
 </DataTemplate>

在你看来

 <ItemsControl ItemsSource="{Binding MyItems}"/>

就这样

于 2012-07-19T12:46:35.650 回答
0

一旦将对象存储在字典中,名称就只是字典中的键。这对编译器没有影响;该名称对于编译器来说是未知的标识符。

这同样适用于您分配给Name控件属性的值。对于编译器来说,这只是一个普通的字符串,也可以是帮助文本;编译器不会仅仅因为调用了该属性就认为它有任何特殊性Name

您可以使用表达式从字典中检索对象,例如a["myName"]; Name您可以通过遍历所有控件并比较其属性的值来找到具有特定名称(根据属性)的控件Name

如果您必须经常访问这些控件,则可能值得设置一个额外的字典,您可以在其中按名称存储控件(例如Dictionary<string, TextBox>)。

于 2012-07-19T12:25:58.467 回答
0

其他答案中提供了很多解决方法;他们或多或少地解决了你的问题。另一种解决方法:

foreach (string name in a.Keys){
    StackPanel SP = new StackPanel();
    TextBox TB1 = new TextBox();
    TextBox TB2 = new TextBox();
    SP.Children.Add(TB1);
    SP.Children.Add(TB2);
    // ... Content to TextBoxes
    TB2.Name = name;
    MainCheckBox.Clicked += (sender, e) => {
        TB2.Height = MainCheckBox.IsChecked ? 300 : 0;
    }
}

但是,让我们看看正确的方法应该是什么。

首先,您需要以可绑定的形式呈现数据项。这意味着要么派生自DependencyObject要么实现INotifyPropertyChanged。其次,您需要将对象放入ObservableCollection. 然后,您可以使用不同的容器,例如ListViewListBox用于显示数据集合。对于表示数据项的类型,您需要创建一个DataTemplate,您可以在其中放置您需要的任何自定义逻辑。

您会发现这是一项相当多的工作,因此我不建议将这种方法用于非常小的应用程序;但是,随着您的应用程序的增长,这种方法将显示出它的好处。

于 2012-07-19T12:31:41.330 回答