C# 访问在运行时创建的控件

C# 访问在运行时创建的控件,c#,wpf,wpf-controls,C#,Wpf,Wpf Controls,我是c#和wpf的新手 如果我在XAML中创建一个控件,我可以在代码中的任何地方访问它的属性。 但是,如果我在运行时创建一个控件,当我尝试在创建它的方法之外访问它时,它会显示为null public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); Button newBtn = new Button(); newBt

我是c#和wpf的新手

如果我在XAML中创建一个控件,我可以在代码中的任何地方访问它的属性。 但是,如果我在运行时创建一个控件,当我尝试在创建它的方法之外访问它时,它会显示为
null

public partial class MainWindow : Window
{

    public MainWindow()
    {
        InitializeComponent();
        Button newBtn = new Button();

        newBtn.Content = "Test";
        newBtn.Name = "btnTest";
        spTest.Children.Add(newBtn);

    }

    private void WPFButton_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
         //I want to access the button called btnTest and display the name of the button             
    }
}

最简单的方法是在字段中存储对按钮的引用:

public partial class MainWindow : Window 
{
    private Button _newBtn;

    public MainWindow()
    {
        InitializeComponent();
        _newBtn = new Button();

        _newBtn.Content = "Test";
        _newBtn.Name = "btnTest";  // < the name is not needed, because you already have a reference. (so you don't have to use FindControl)
        // and if you want to register the click event.
        _newBtn.Click += Button_Click;
        spTest.Children.Add(_newBtn);
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        MessageBox.Show("Button clicked");
    }

    private void WPFButton_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        //I want to access the button called btnTest and display the name of the button             
        _newBtn.Content = "Test2"; 
    }
}
公共部分类主窗口:窗口
{
专用按钮_newBtn;
公共主窗口()
{
初始化组件();
_newBtn=新按钮();
_newBtn.Content=“测试”;
_newBtn.Name=“btnTest”//<不需要该名称,因为您已经有了一个引用。(因此不必使用FindControl)
//如果你想注册点击事件。
_newBtn.Click+=按钮单击;
spTest.Children.Add(_newBtn);
}
私有无效按钮\u单击(对象发送者,路由目标e)
{
MessageBox.Show(“单击按钮”);
}
私有void WPFButton_MouseUp(对象发送器,System.Windows.Input.MouseButtonEventArgs e)
{
//我想访问名为btnTest的按钮并显示该按钮的名称
_newBtn.Content=“Test2”;
}
}

如果您想存储多个控件,请使用字典或列表。

这里的操作有一些复杂的地方,但这些并不明显。 其中之一是,您不能只定义一些处理程序,它会起作用。 您还必须订阅该活动。 这是一个代理,你正在插入一个事件

就像电器一样,你需要在任何事情发生之前把它插上电源

下面是一些标记和代码,以探索正在发生的事情

因此,我可以看到消息,我将使用一个列表框向其中添加项目。这些将显示为消息列表

    Title="MainWindow" Height="450" Width="800"
    Button.Click="Window_Button_Click">
    <Grid Name="agrid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <ListBox Name="lb"
                 Grid.Column="1"/>
    </Grid>
上面的代码相当快速和肮脏

请注意,冒泡事件处理程序对事件的原始源感兴趣,因为它是向上传递的,而发送方不是按钮

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        Button newBtn = new Button();

        newBtn.Content = "Test";
        newBtn.Name = "btnTest";
        agrid.Children.Add(newBtn);
        newBtn.MouseUp += NewBtn_MouseUp;
        newBtn.PreviewMouseDown += NewBtn_PreviewMouseDown;
    }

    private void NewBtn_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        Button btn = sender as Button;
        string theName = btn?.Name ?? "Something was Preview Mouse Downed but I don't know what";
        lb.Items.Add($"Button PREVIEW MouseUp {theName}");
    }

    private void NewBtn_MouseUp(object sender, MouseButtonEventArgs e)
    {
        Button btn = sender as Button;
        string theName = btn?.Name ?? "Something was Mouse Upped but I don't know what";
        lb.Items.Add($"Button MouseUp {theName}");
    }

    private void Window_Button_Click(object sender, RoutedEventArgs e)
    {
        Button btn = e.OriginalSource as Button;
        string theName = btn?.Name ?? "Something was CLICKED in the window but I don't know what";
        lb.Items.Add($"Window Button Click {theName}");
    }
}
f5旋转她并点击按钮

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        Button newBtn = new Button();

        newBtn.Content = "Test";
        newBtn.Name = "btnTest";
        agrid.Children.Add(newBtn);
        newBtn.MouseUp += NewBtn_MouseUp;
        newBtn.PreviewMouseDown += NewBtn_PreviewMouseDown;
    }

    private void NewBtn_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        Button btn = sender as Button;
        string theName = btn?.Name ?? "Something was Preview Mouse Downed but I don't know what";
        lb.Items.Add($"Button PREVIEW MouseUp {theName}");
    }

    private void NewBtn_MouseUp(object sender, MouseButtonEventArgs e)
    {
        Button btn = sender as Button;
        string theName = btn?.Name ?? "Something was Mouse Upped but I don't know what";
        lb.Items.Add($"Button MouseUp {theName}");
    }

    private void Window_Button_Click(object sender, RoutedEventArgs e)
    {
        Button btn = e.OriginalSource as Button;
        string theName = btn?.Name ?? "Something was CLICKED in the window but I don't know what";
        lb.Items.Add($"Window Button Click {theName}");
    }
}
那里有一个惊喜等着你

没有来自mouseup的消息

这是因为按钮设计为单击而不是鼠标向下和鼠标向上。 ButtonBase中的代码会处理一些鼠标事件,因为它会处理这些事件,所以处理程序不会启动


希望这能解释一些关于事件的事情

不过,有几件事我也应该提到

几乎所有的wpf开发都使用MVVM,并将命令绑定到按钮的command属性,而不是使用事件

添加动态内容通常也不会在这样的代码中完成

有许多选项包括datatemplates。这在名为viewmodel first的方法中非常常见


您还可以通过将xaml作为字符串转换为控件来构建UI。这是构建UI的推荐方法,当您无法使用样式或模板时,UI必须是动态的。现在深入研究这个东西可能还为时过早,但仅供参考

如果它是创建的,并且您有一个对它的引用,那么该控件不能为null,除非其他东西将其设置为null。该请求是关于用另一种方法访问按钮实例。没有MVVM受到质疑。过于臃肿。命令的execute方法将是“另一个”方法。一个通常不需要使用它绑定到的按钮实例的程序。