How to distinguish which button was being clicked from a user control? - c#

I have a user control with two buttons (Add, Delete). When accessed from the main window, how do I know which button were being clicked?
btnAdd had a method while btnDelete has another method that should be invoked.

Create two separate Command for button add and delete in MainWindow
And you can bind your command in userControl like this:
<Button Command={Binding AddCommand}/>
and set the datacontext of Mainwindow to itself inside XAML or in a constructer
this.datacontext = this;
For more information on how to create Command see this and this

If I understand your issue correctly, you could cast the sender argument in the event handler:
private void Button_Click(object sender, RoutedEventArgs e)
{
Button button = sender as Button;
if (button.Name == "btnAdd ")
{
//add button was clicked...
}
else if (button.Name == "btnDelete")
{
}
}
<Button x:Name="btnAdd" Content="Add" Click="Button_Click" />
<Button x:Name="btnDelete" Content="Delete" Click="Button_Click" />

Related

UWP: TextBox inside Button, how to prevent SpaceBar from triggering the Click event?

i want to put a TextBox, together with a Label and a SymbolIcon into a Button, so that the whole thing is clickable. at the start you can only see the label and the symbol. By clicking on the button, the label gets hidden and the textBox appears, where you can type some text. By clicking again the label comes up again with the new entered text and the TextBox disappears.
My problem is, that by setting the focus to the TextBox, the button (parent) also seems to get into focus, because everytime you press the spacebar, the Click Event of the button fires. I dont want this to happen, while the TextBox has focus.
XAML
<Button Click="ToggleTopic"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch">
<Grid>
<TextBlock x:Name="textBlockInfoTopic"
Text=""
HorizontalAlignment="Left"
Margin="100,0,100,0"/>
<TextBox x:Name="textBoxTopic"
PlaceholderText="enter Topic..."
HorizontalAlignment="Stretch"
Margin="100,0,100,0"
Visibility="Collapsed"/>
<SymbolIcon x:Name="symbolTopicButton"
Symbol="Add"
HorizontalAlignment="Right"/>
</Grid>
</Button>
C#
private void ToggleTopic(object sender, RoutedEventArgs e)
{
if (textBoxTopic.Visibility == Visibility.Visible)
{
//non edit mode
textBoxTopic.Visibility = Visibility.Collapsed;
textBlockInfoTopic.Visibility = Visibility.Visible;
symbolTopicButton.Symbol = Symbol.Add;
textBlockInfoTopic.Text = textBoxTopic.Text;
}
else
{
//edit mode
textBoxTopic.Visibility = Visibility.Visible;
textBoxTopic.Focus(FocusState.Programmatic);
textBlockInfoTopic.Visibility = Visibility.Collapsed;
symbolTopicButton.Symbol = Symbol.Go;
textBlockInfoTopic.Text = "";
}
}
I only want to prevent the triggering of the event through the spaceBar. The return key should trigger the event.
Thanks for helping me!
D.
From official document,
If a button has keyboard focus, pressing the Enter key or the Space key also raises the Click event. You generally can't handle low-level PointerPressed events on a Button because it has the Click behavior instead.
If you want to prevent SpaceBar from triggering the Click event, you could override OnProcessKeyboardAccelerators method of Button like the following.
public class MyButton : Button
{
protected override void OnProcessKeyboardAccelerators(ProcessKeyboardAcceleratorEventArgs args)
{
if(args.Key == VirtualKey.Space)
{
args.Handled = true;
}
base.OnProcessKeyboardAccelerators(args);
}
}
Usage
<local:MyButton Click="ToggleTopic"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch">
<Grid IsTapEnabled="False" >
<TextBlock x:Name="textBlockInfoTopic"
Text=""
HorizontalAlignment="Left"
Margin="100,0,100,0"/>
<TextBox x:Name="textBoxTopic"
PlaceholderText="enter Topic..."
HorizontalAlignment="Stretch"
Margin="100,0,100,0"
Visibility="Collapsed"/>
<SymbolIcon x:Name="symbolTopicButton"
Symbol="Add"
HorizontalAlignment="Right"/>
</Grid>
</local:MyButton>

Get TextBlock inside Button

I have a Button with a TextBlock embedded inside. When the Button is clicked, I want to be able to fetch the TextBlock inside it and modify it's members.
Here is how my button is setup:
<Button Click="Select_Click" Style="{StaticResource ButtonStyle}" HorizontalAlignment="Left" Padding="0,20,20,20">
<TextBlock Text="My text" FontSize="20" Style="{StaticResource TextBlockStyle}"/>
</Button>
In my code behind I want to be able to access the embedded TextBlock:
public void Select_Click(object sender, RoutedEventArgs e)
{
// Get the `TextBlock` from `sender` here
}
I've taken a look at the visual tree of the Button but I'm not seeing the TextBlock. I called GetVisualChildren() on the Button but I only see a Grid and no way to get to the Textblock.
The content of the Button is stored in its Content property and in your case, the TextBlock is the content of the Button.
public void Select_Click(object sender, RoutedEventArgs e)
{
Button button = (Button)sender;
TextBlock textBlock = (TextBlock)button.Content;
}
Just do some casting and it's pretty simple
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Establish_handlers();
}
void Establish_handlers()
{
Mybutton.Click += Mybutton_Click;
}
private void Mybutton_Click(object sender, RoutedEventArgs e)
{
Button clicked_button = (Button)sender;
TextBlock desired_text = (TextBlock)clicked_button.Content;
Textbox_Show_Button_Content.Text = desired_text.Text;
}
}
<StackPanel>
<Button x:Name="Mybutton">
<TextBlock>Hello</TextBlock>
</Button>
<TextBox x:Name="Textbox_Show_Button_Content"></TextBox>
</StackPanel>

WPF - switching between two way and one way bindings?

In my 'View' I have a TextBox bound to a ViewModel's string property.
I want to add a submit button to the View, so the underlying ViewModels string property is only updated when this is pressed.
To further complicate things, this TextBox is inside a DataGrid. I think setting the bindings UpdateSourceTrigger to Explicit may be the answer but I can't see how this would work.
Any alternative solution would be to switch the ViewModels String with a TextBox - meaning I would manually populate data.
You can bind button to command and pass text of textbox as parameter.
<TextBox x:Name="textBox"></TextBox>
<Button Content="Button" Command="{Binding MyCommand}" CommandParameter="{Binding ElementName=textBox, Path=Text}"/>
In your ViewModel:
public ICommand MyCommand
{
get
{
return new RelayCommand((textBoxText) =>
{
if (...)
{
//somelogic;
}
});
}
}
In the Button you access the row via the DataContext
private void ButtonRevise_Click(object sender, RoutedEventArgs e)
{
Button btn = (Button)sender;
GabeLib.SearchItem srchItem = (GabeLib.SearchItem)btn.DataContext;

Contextmenu - disable right click to open it

I have such xaml code:
<Grid x:Name="boardGrid">
<Grid.ContextMenu>
<ContextMenu Opacity="0.7" x:Name="menuContext">
</ContextMenu>
</Grid.ContextMenu>
</Grid>
I generate grid's items in code behind. What I want is to disable context menu opening on right click. I want to open it when certains conditions occur.
This is what I have in .cs file:
generating Unit's objects and putting them into Grid;
each object has unit.MouseRightButtonUp += unit_MouseRightButton
void unit_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
if (CurrentGame.CurrentPlayer.HasTurn == false) return;
.....
ContextMenu.IsOpen = true;
}
So it means that Contextmenu should be open only if condition is fulfilled but it opens anyway.
You can set the attached property ContextMenuService.IsEnabled to false. Then you can manually popup the ContextMenu.
You must set that property for the GUI element that owns the menu. Setting it for the menu itself will do nothing.
<Grid x:Name="boardGrid" ContextMenuService.IsEnabled="false">
<!-- ... -->
</Grid>
void unit_MouseRightButtonUp(object sender, MouseButtonEventArgs e) {
if (CurrentGame.CurrentPlayer.HasTurn == false) return;
.....
boardGrid.ContextMenu.IsOpen = true;
}

Attached events in WPF: an OK button always requires 2 clicks to close

I have the following XAML
<Window x:Class="SimpleAttahEvent.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow">
<Grid>
<StackPanel Margin="5" Name="stackButton" ButtonBase.Click="DoSomething">
<Button Name="cmd1" Tag="The first button"> Command 1</Button>
<Button Name="cmd2" Tag="The second button"> Command 2</Button>
<Button Name="cmd3" Tag="The third button"> Command 3</Button>
</StackPanel>
</Grid>
</Window>
...With the following code to handle the attached events.
namespace SimpleAttahEvent
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
stackButton.AddHandler(Button.ClickEvent, new RoutedEventHandler(DoSomething));
}
private void DoSomething(object sender, RoutedEventArgs e)
{
Console.WriteLine(Button.ClickEvent.RoutingStrategy);
Console.WriteLine(TextBox.PreviewKeyDownEvent.RoutingStrategy);
if (e.Source == cmd1)
{
MessageBox.Show("First button is clicked");
}
if (e.Source == cmd2)
{
MessageBox.Show("Second button is clicked");
}
if (e.Source == cmd3)
{
MessageBox.Show("Third button is clicked");
}
}
}
}
These produce a dialog box with 3 buttons stacked vertically. When I click one of the button, a messagebox comes up with an OK button. However, the OK button on the dialogue box won't close unless I clicked it twice. Did I do this implicitly from the code given above?
Edit - Additional Info:
When I do this instead
private void DoSomething(object sender, RoutedEventArgs e)
{
object tag = ((FrameworkElement)sender).Tag;
MessageBox.Show((string)tag);
}
..it still require 2 clicks to close the message box.
Your problem is that you are doubling your handler. You do not have to click twice on the same OK; you are clicking on OK, which closes the first message. Then, the event is handled again and you get another exact same message that you have to click OK on. If you add + DateTime.Now to your messages you will see that this is indeed a second message
I missed this line on my first glance:
stackButton.AddHandler(Button.ClickEvent, new RoutedEventHandler(DoSomething));
Which is the same as the ButtonBase.Click from this line
<StackPanel Margin="5" Name="stackButton" ButtonBase.Click="DoSomething">
Choose one way to attach to event handlers and stick to it. Mixing them up is just going to cause confusion.

Categories

Resources