I'm a C# beginner and am trying to implement a numeric pad in WPF. It consists of 10 similar buttons:
<Button Content="0" Name="button0" Click="anyButtonClicked" />
<Button Content="1" Name="button1" Click="anyButtonClicked" />
<Button Content="2" Name="button2" Click="anyButtonClicked" />
...
<Button Content="9" Name="button9" Click="anyButtonClicked" />
What is the best practise to handle all those buttons? Do I build a function in the code behind for each one (Which would be mostly boring and repeating myself), or do I build one to handle any button clicked?
In the second case, how do I identify which button was clicked? What property of the sender object do I need to access?
If you want to use code behind then you can hook it up to a single event handler, you can then cast sender to a Button (or a FrameworkElement) and check its Name property.
Expanding on Goblin's answer below; if you want to stick with code behind and events you can define the event on a parent panel:
<StackPanel Button.Click="anyButtonClicked">
<Button Content="0" Name="button0"/>
<Button Content="1" Name="button1"/>
<Button Content="2" Name="button2"/>
...
<Button Content="9" Name="button9"/>
</StackPanel>
Then use e.OriginalSource, cast as a Button or FrameworElement, to retrieve the name.
private void anyButtonClicked(object sender, RoutedEventArgs e)
{
var source = e.OriginalSource as FrameworkElement;
if (source == null)
return;
MessageBox.Show(source.Name);
}
Alternatively you could take the MVVM approach, have a single command that all of your buttons are bound to, and pass a CommandParameter to differentiate them.
You handle the Button.Click event in the Parent control:
<StackPanel Button.Click="anyButtonClicked">
<Button Content="0" Name="button0"/>
<Button Content="1" Name="button1"/>
<Button Content="2" Name="button2"/>
...
<Button Content="9" Name="button9"/>
</StackPanel>
Then in your eventhandler - you can check e.OriginalSource for the button pressed.
EDIT: As for your question as to how to handle it - you could use the Content-property of the button pressed to figure out the key and then use that to perform your logic.
You really need to go by the Command approach because you may need it for key presses also.
Related
I'm trying to change the property materialDesign:ButtonProgressAssist.IsIndeterminate via C# code.
I haven't found any property like that in the Button object.
This is the buttons code:
<Button x:Name="loginButton" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,0,0,100" Width="100"
Style="{StaticResource MaterialDesignRaisedButton}"
materialDesign:ButtonProgressAssist.Value="-1"
materialDesign:ButtonProgressAssist.IsIndicatorVisible="True"
materialDesign:ButtonProgressAssist.IsIndeterminate="false" />
I want to set the IsIndeterminate Property to true when it gets clicked.
I don't understand, why i always find it out shortly after i ask it on StackOverflow...
But here's the solution:
MaterialDesignThemes.Wpf.ButtonProgressAssist.SetIsIndeterminate(loginButton, true);
I have 4 radio buttons that every one of them shows a different list in a combobox that attached to them. The radio button should be available only after pressing a some button. I want one of the radio button to be chosen and than the last row on the combo list to be chosen automatically.
MAINWINDOWS.XAML
<!--RadioButtons-->
<RadioButton x:Name="RadioButtonA" GroupName="Button" Content="A" Margin="0,5,0,0" Grid.Column="0" Click="RadioButtonA_Click" />
<RadioButton x:Name="RadioButtonB" GroupName="Button" Content="B" Margin="0,20,0,0" Grid.Column="0" Click="RadioButtonB_Click"/>
<RadioButton x:Name="RadioButtonC" GroupName="Button" Content="C" Margin="0,35,0,0" Grid.Column="0" Click="RadioButtonC_Click"/>
<RadioButton x:Name="RadioButtonD" GroupName="Button" Content="D" Margin="0,50,0,0" Grid.Column="0" Click="RadioButtonD_Click"/>
<!--ComboBox-->
<ComboBox
x:Name="ComboBox"
IsEnabled="false"
Grid.Column="1"
Width="240"
Height="30"
VerticalAlignment="Top" Margin="0,8,0,0"
SelectionChanged="ComboBoxSelectionChanged" >
</ComboBox>
ViewModel: Example for one of the radiobuttons
private void RadioButtonA_Click(object sender, RoutedEventArgs e)
{
IdComboBox.SelectedValue = string.Empty;
IdComboBox.IsEnabled= true;
IdComboBox.Items = AList;
currentIdentifier = Identifier.A;
}
You mentioned "ViewModel", but you actually don't use MVVM.
Using event handlers to set state of many related controls is a doomed way - because complexity increases in proportion to the square of the amount of controls. You have to use MVVM, the approach when properties of controls are projected to a property of a model. Then you can use triggers to set controls state depending on the model property values. Or, if you consider triggers too verbose, you can use QuickConverter, this library helps to simplify code.
Even if you don't like/cannot use any of them, please, use triggers to set state of comboboxes.
I'm quite new to c# wpf and have a problem.
I have used the answer from this post to duplicate a Grid control. The grid control contains a button. It looks like it is being duplicated correctly.
When the original control's button is pressed, the click event is handled which calls a method in the window's code.
When the copy of the control's button is pressed, the click event is not fired and the method is not called. This is confusing me as I want it to call that same method.
Maybe the event handling data is not being copied properly? Is there a way around this?
Both the origional grid and copied grid (containing the buttons) are children of another grid.
Edit:
This is the xaml for the origional grid which contains a button:
<Grid Name="TempTab" DockPanel.Dock="Left" HorizontalAlignment="Left" Margin="5,5,5,0">
<Rectangle Fill="Black" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stroke ="White" Margin="0,0,-2,0">
</Rectangle>
<Grid>
<DockPanel LastChildFill="False">
<TextBlock Foreground="White" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="3,0,3,3">Some Text</TextBlock>
<Button Width="50" BorderBrush="{x:Null}" Foreground="{x:Null}" BorderThickness="0" Margin="3,0,0,0" Click="tabdowntest">
<Button.Background>
<ImageBrush ImageSource="TopMenuBar_Close.png" Stretch="Uniform"/>
</Button.Background>
</Button>
</DockPanel>
</Grid>
</Grid>
This grid is a child of a DockPanel with name 'TabsDock'.
It is being copied with the following code:
string gridXaml = XamlWriter.Save(TempTab);
StringReader stringReader = new StringReader(gridXaml);
XmlReader xmlReader = XmlReader.Create(stringReader);
Grid newTab = (Grid)XamlReader.Load(xmlReader);
TabsDock.Children.Add(newTab);
This is the code for the 'Click' event handler which should be called when the either the origional or the copied button's are pressed. But it is only called for the origional:
private void tabdowntest(object sender, MouseButtonEventArgs e)
{
Console.WriteLine("Button Pressed");
}
The bindigs are not set, you need to set them (comment in the orig post):
To be clear, this is only half the solution (as it stood back in 08). This will cause bindings to be evaluated and the results be serialized. If you wish to preserve bindings (as the question asked) you must either add a ExpressionConverter to the Binding type at runtime (see the second part of my question for the relevant link) or see my own answer below for how to do it in 4.0.
I'm trying to programatically create a button flyout, within my XAML I have:
<Page.Resources>
<Button x:Key="LaunchFlyout" Content="LAUNCH">
<Button.Flyout>
<Flyout Placement="Top">
<Grid Width="200" Height="200">
<StackPanel>
<Rectangle Fill="Red" Width="100" Height="100" />
<Rectangle Fill="Green" Width="100" Height="100" />
</StackPanel>
</Grid>
</Flyout>
</Button.Flyout>
</Button>
</Page.Resources>
Nested within grids I have:
<Grid x:Name="launchBtn_grid" Grid.Column="1">
</Grid>
And then in my code within the Page_Loaded method I have:
bool hasContainer = localSettings.Containers.ContainsKey("appStatus");
if (!hasContainer) {
Button button = (Button)this.Resources["LaunchFlyout"];
launchBtn_grid.Children.Add(button);
}
else {
Button button = new Button();
button.Content = "LAUNCH";
button.Click += launch_btn_Click;
launchBtn_grid.Children.Add(button);
}
When I debug this, it reaches the IF statement and reaches this line launchBtn_grid.Children.Add(button); and then I get this error Element is already the child of another element.
Does anyone understand why? I have already looked and they dont already exist so I don't understand why it is giving me this error. Does anyone know what I am doing wrong?
I'm not sure in what context/use case your are doing that, but it feels weird to me to have an actual control as a Resource (not a DataTemplate, Style, etc).
If you only want to have 1 button of the 2 different template, why not switch Visibility on the 2 instead of loading controls from your code behind ?
Going forward with the idea, just add both buttons in the Grid within your XAML and switch their Visibility according to the setting you read.
There is a BooleanToVisibilityConverter within the framework to help you with this.
I'm doing integration tests with help of UI Automation. I need to check if a user control has focus (IsFocused = true). Is it possible ? I tried using AutomationElement.FocusedElement, but as far as I checked it returns different control (probably outside of my app).
My control:
<UserControl GotFocus="UserControl_GotFocus" Focusable="True">
<DockPanel>
<Button DockPanel.Dock="Right" Content=">" IsTabStop="False" Focusable="False" Click="TextButton_Click" />
<TextBox Text="{Binding Text}" x:Name="textBox" />
</DockPanel>
code behind:
private void UserControl_GotFocus(object sender, RoutedEventArgs e)
{
textBox.Focus();
Keyboard.Focus(textBox);
}
You can get the AutomationElement associated with the control you care about, then get the AutomationElement.FocusedElement and compare them. If they are the same, then it is focused.
Also, AutomationElement.Current should have a HasKeyboardFocus property. You can see if that gives you the information you need.