如何在c#(WPF)中与“动态创建的对象”进行交互

时间:2012-07-19 12:21:55

标签: c# wpf

我对C#很陌生,并且遇到了以下问题:我的程序在运行时创建了一个对象字典(大小未知)。对于我想创建一个内部有两个TextBox的StackPanel元素的每个对象,我的操作如下:

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

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

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

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

我认为我在做一些概念错误的事情,那么根据数据创建此类事物的更好方法是什么?

提前致谢!

6 个答案:

答案 0 :(得分:3)

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

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

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

myTextBoxes.Add(name, TB2);
然后,您可以像这样访问TextBox

myTextBoxes["TextBoxName"].Height = 300;

答案 1 :(得分: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
        }

答案 2 :(得分:1)

你可以搜索WPF的VisualTree来查找带有你名字的对象(我有一些你可能觉得有用的VisualTreeHelpers on my blog,并且它们会显示一些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>

然后当您创建TextBoxes时:

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

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

<ItemsControl ItemsSource="{Binding Keys}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBox ... />
                <TextBox Style="{StaticResource SecondTextBoxStyle}" ... />
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

答案 3 :(得分:1)

简单的方法是获取动态创建的对象 - 将它们放在一个集合中 - 创建一个datatemplate,以便wpf知道如何渲染 - 并将这些集合放到itemscontrol中。有些人首先用viewmodel调用这个mvvm;)

动态对象包装器

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

用于处理集合和检索集合数据的viewmodel

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

那就是

答案 4 :(得分:0)

将对象存储在字典中后,名称就是字典中的键。这对编译器没有任何影响;该名称不是编译器的已知标识符。

这同样适用于您为控件的Name属性赋值的值。对于编译器来说,这只是一个普通的字符串,也可以是一个帮助文本;编译器认为它没有任何特殊之处,因为该属性被称为Name

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

如果您经常访问这些控件,则可能需要设置一个附加字典,以便按名称存储控件(例如Dictionary<string, TextBox>)。

答案 5 :(得分: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,您可以在其中放置所需的任何自定义逻辑。

你看,这是相当多的工作,所以我不推荐这种方法用于真正的小应用程序;然而,随着您的应用程序的增长,这种方法将显示其优势。