Reputation: 19
I am new to c# and wpf.
If I create a control in XAML, I can access its properties anywhere in my code.
However, if I create a control at runtime, it shows up as null
when I try to access it outside the method it was created.
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
}
}
Upvotes: 1
Views: 313
Reputation: 22038
The most easiest way is storing a reference to the button in a field:
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";
}
}
If you want to store multiple controls, use a dictionary or list.
Upvotes: 0
Reputation: 12276
There are several complications to what you're doing here which aren't immediately obvious. One of which is you can't just define some handler and it'll work. You also have to subscribe it to the event. It's a delegate you're sort of plugging into an event.
Like an electrical appliance, you need to plug it in before anything is going to happen.
Here's some markup and code to explore what's going on.
So I can see messages I'll use a listbox which I'll add items to. These will be displayed as a list of messages.
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>
I hook up a button click handler at window level. This will handle click events that bubble up to it from anywhere inside the window. Read up on bubbling and tunnelling routed events if this is a new concept to you.
https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/routed-events-overview
Then, I'm going to dynamically add a button. This will default to column 0 of the grid and appear on the left.
As you will see if you try it.
I also subscribe two more events of the button.
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}");
}
}
The code above is rather quick and dirty.
Notice a bubbling event handler is interested in the originalsource of the event since it's passed up the tree and sender isn't going to be the button.
f5 to spin her up and click the button.
There is a surprise waiting for you there.
No message from mouseup.
This is because the button is designed to be clicked rather than mousedown and mouse upped. Code in ButtonBase does stuff with some of the mouse events and because it handles them, your handler will not fire.
So that's hopefully explained a few things about events.
There are a few things I should also mention though.
Almost all wpf development uses MVVM and will bind a command to the command property of a button rather than using events at all.
Adding dynamic content is also not usually done in code like this.
There are a number of options which include datatemplates. This is very common with an approach called viewmodel first.
You can also build UI by translating xaml as a string into controls. This is the recommended way to build UI which must be dynamic when you cannot use styling or templating. It's probably too early for you to delve into this stuff but FYI https://social.technet.microsoft.com/wiki/contents/articles/28797.wpf-dynamic-xaml.aspx
Upvotes: 1