C# WPF背后的代码-如何访问UI元素或将其传递到事件处理程序?

C# WPF背后的代码-如何访问UI元素或将其传递到事件处理程序?,c#,wpf,user-interface,C#,Wpf,User Interface,不管是好是坏,我只在代码隐藏中构建WPF UI。我在堆栈面板中有一个按钮和一个文本块。单击按钮后,会使用一些信息更新文本块。如果我使TextBlock成为类的成员,它将成功工作。然而,仅仅是到处声明全局UI元素感觉就像是一条简单的出路。是否有办法在MainWindow()中实例化TextBlock,并在button click事件中仍然可以访问它 以下伪代码起作用: public partial class MainWindow : Window { public TextBlock m

不管是好是坏,我只在代码隐藏中构建WPF UI。我在堆栈面板中有一个按钮和一个文本块。单击按钮后,会使用一些信息更新文本块。如果我使TextBlock成为类的成员,它将成功工作。然而,仅仅是到处声明全局UI元素感觉就像是一条简单的出路。是否有办法在MainWindow()中实例化TextBlock,并在button click事件中仍然可以访问它

以下伪代码起作用:

public partial class MainWindow : Window
{
    public TextBlock myTextBlock;

    public MainWindow()
    {

        StackPanel mainStackPanel = new StackPanel();

        Button myButton = new Button();

        myButton.Click += NewButton_Click();

        mainStackPanel.Children.Add(myTextBlock);

        mainStackPanel.Children.Add(myButton);

        Content = mainStackPanel;

    }

    private void NewGridButton_Click(object sender, RoutedEventArgs e)
    {
        myTextBlock.Text = "Some Text"
    }

}

然而,我很好奇,是否也有可能做到这一点:


public partial class MainWindow : Window```
{
    public MainWindow()
    {

        StackPanel mainStackPanel = new StackPanel();

        Button myButton = new Button();

        TextBlock myTextBlock = New TextBlock();

        myButton.Click += NewButton_Click();

        mainStackPanel.Children.Add(myTextBlock);

        mainStackPanel.Children.Add(myButton);

        Content = mainStackPanel;

    }

    private void NewGridButton_Click(object sender, RoutedEventArgs e)
    {
        //Somehow Access the myTextBlock from MainWindow here in order to set the text?

        myTextBlock.Text = "Some Text" // This would not compile.
    }

}

为简洁起见,这里的代码只是示例,并没有完全起作用。提前感谢您提供有关此主题的任何信息



编辑-跟进。这里答案的一致性似乎表明我对这个问题考虑过度了。表示我希望使用的UI元素的私有类变量似乎是一种普遍接受的(不一定是惰性的)声明和访问UI元素的方法。感谢所有花时间回顾和评论的人。

我认为将事件代码移动到方法

private void NewGridButton_Click(object sender, RoutedEventArgs e)
{

    NewGridButtonClick();

}

 private void NewGridButtonClick()
 {
    myTextBlock.Text = "Some Text" // This would not compile.
 }
然后从应用程序中的任何位置调用它

 private void SomeButton_Click(object sender, RoutedEventArgs e)
{

    MainWindow.NewGridButtonClick();

}

在这种情况下,使用局部作用域变量并不是一件坏事(根据您最初的示例)。它可能感觉很难看,但本质上是通过在XAML文件中定义内容在后台创建的


另一种选择是,请参见,其中包含用于定位控件的代码以及对VisualTreeHelper的引用,VisualTreeHelper可以提供帮助。然而,在我看来,这两种选择都不如最初的想法那么优雅。

这是对WPF的一种可怕的滥用,我怀疑你已经知道了这一点。但如果您坚持,您可以在创建TextBlock时为其命名:

myTextBlock.Name = "MyTextBlock";
然后,您可以随时遍历可视树以找到它。添加到类中,然后在单击处理程序中执行此操作:

private void MyButton_Click(object sender, RoutedEventArgs e)
{
    var textBlock = FindChild<TextBlock>(this, "MyTextBlock");
    textBlock.Text = "Hello World!";
}
虽然在WPF中仍然不是这样做的“正确”方式,但至少您不再需要遍历整个树来查找您要查找的元素:

var textBlock = this.Children["MyTextBlock"] as TextBlock;
textBlock.Text = "Hello World!";

如果不在字段中存储对
TextBlock
的引用,则需要以某种方式动态获取对它的引用

有多种方法可以做到这一点。例如,您可以从根
面板的
子类
集合进入:

private void NewGridButton_Click(object sender, RoutedEventArgs e)
{
    TextBlock myTextBlock = (Content as Panel).Children.OfType<TextBlock>().FirstOrDefault();
    if (myTextBlock != null)
        myTextBlock.Text = "Some Text";
}

但是,这两种方法都不比将引用存储在字段中“更好”。使用字段,您不必执行任何动态查找。

我认为您没有抓住问题的关键。这是关于从其他方法以编程方式添加到视图中的元素,而无需创建变量来保存这些元素。如果使用MVVM,则会更简单,只需将MainWindow注册为singleton,然后在任何需要的vie中获得它,并运行方法withinI建议您使用MVVM架构。感谢僵尸羊花时间发表评论。我最终寻求WPF的最佳实践,似乎我已经严重过度考虑了这一点。我想,通过为我想在别处操作的每个元素声明类变量,我只是对代码很懒惰。看起来替代方案不必要地更加复杂。我想我想得太多了。再次感谢。我从来没有这样工作过。请注意,编译器会将所有XAML代码翻译成C代码。您可以做的是创建一个演示应用程序并研究生成的代码。这可能是一个灵感的来源。一般来说,为什么不使用XAML?我不喜欢XAML,但它是创建UI层的最简单方法不是全局的,也不是到处都是。它是MainWindow类中的一个字段,每个窗口实例的值不同。不过最好把它定为私人的<代码>私有文本块myTextBlock就可以了<代码>
只在隐藏的生成字段中提供相同的私有字段code@RudolfJan这是一个有趣的建议,也是我对WPF的总体期望。为了更好地理解实际发生的事情,我尝试用代码来创建布局。似乎普遍的共识与我的看法不一致,但谢谢你花时间发表评论。@ASh你是对的,这不是全球性的,我说错了。我所说的“到处都是”的意思是,如果您必须对实际应用程序中要使用的每个元素都这样做,那么它可能会开始看起来像是太多的类变量,而这些变量只能从任何函数访问。不过,设置为“私人”是一个很好的建议。感谢您抽出时间发表评论。感谢Mark抽出时间发表评论。我不是WPF专家,只是希望学习最佳实践。是否因为没有使用XAML,所以WPF的使用不好?我想用代码隐藏来制作UI的想法是为了更好地理解它的实际情况。然而,人们似乎并不同意这一点。我想总的来说,如果可能的话,遍历可视化树是我很好奇的,你已经回答了。谢谢。很高兴能帮忙!如果只是为了实践学习,那么就去做吧,它肯定会有助于教授XAML在幕后所做的事情。然而,对于现实世界的应用程序,WPF被设计为使用数据绑定。甚至事件处理程序(例如用于单击按钮的事件处理程序)也得到了支持,以促进遗留代码的升级(MS知道,他们将在一次点击中强制实施如此重大的更改,这是一场斗争)。在一个“纯”的MVVM应用程序中,您实际上可以将所有的window/control.cs文件保留为空(或删除),只保留XAML文件,并且它仍然可以正常构建。感谢mm8花时间发表评论。最终,我在寻找动态的方法来查找元素,而不必停止
var textBlock = this.Children["MyTextBlock"] as TextBlock;
textBlock.Text = "Hello World!";
private void NewGridButton_Click(object sender, RoutedEventArgs e)
{
    TextBlock myTextBlock = (Content as Panel).Children.OfType<TextBlock>().FirstOrDefault();
    if (myTextBlock != null)
        myTextBlock.Text = "Some Text";
}
public MainWindow()
{
    ...

    TextBlock myTextBlock = new TextBlock();
    RegisterName("myTextBlock", myTextBlock);

    ...
}

private void NewGridButton_Click(object sender, RoutedEventArgs e)
{
    TextBlock myTextBlock = FindName("myTextBlock") as TextBlock;
    if (myTextBlock != null)
        myTextBlock.Text = "...";
}