adding content to a button click in wpf - c#

Why cant I do this in wpf?
button1Click.Content = "Hover over me";
or
ToolTip t = new ToolTip();
t.Content = "Something helpful";
button1Click.Tooltip = t;
I populate my widow with populate buttons on initialization I then have a foreach loop that adds buttons like so:
foreach (var routedEventHandler in new RoutedEventHandler[] { button1Click, button2Click, button3_Click })`
Now in this area I apply styles to the buttons all in one go like so:
public void populateButtons()
{
double xPos;
double yPos;
Random ranNum = new Random();
foreach (var routedEventHandler in new RoutedEventHandler[] { button1Click, button2Click, button3_Click })
{
Button foo = new Button();
Style buttonStyle = Window.Resources["CurvedButton"] as Style;
int sizeValue = 100;
foo.Width = sizeValue;
foo.Height = sizeValue;
xPos = ranNum.Next(200);
yPos = ranNum.Next(250);
foo.HorizontalAlignment = HorizontalAlignment.Left;
foo.VerticalAlignment = VerticalAlignment.Top;
foo.Margin = new Thickness(xPos, yPos, 0, 0);
foo.Style = buttonStyle;
foo.Click += routedEventHandler;
LayoutRoot.Children.Add(foo);
}
}
}
}
But when I try this:
private void button3_Click(object sender, RoutedEventArgs e)
{
((Button)sender).ToolTip = t;
}
It only activates when a button is pressed? (Thanks #H.B)
However when I paste the tooltip code in my populate buttons:
Random ranNum = new Random();
foreach (var routedEventHandler in new RoutedEventHandler[] { button1Click, button2Click, button3_Click })
{
Button foo = new Button();
ToolTip t = new ToolTip();
t.Content = "Something helpful";
foo.ToolTip = t;
It works? But the problem is that doing it this way sets all buttons with the same tooltip and or button content! which I dont want, but I cant find a way around it?
So to summarize I can either set all buttons with the same tooltip message or button content within "populateButtons()" or I can only set tooltips and button content when the button has been pressed.
Is there no method possible that can add content to a named button?
Like my initial attempt:
button1Click.Content = "Home Button";
or
button1Click.ToolTip = "Hover over me";
Why on earth cant you set content and tooltips for specific buttons on initialization?

If you want to go this route then you can add a handler for Loaded event:
foo.Click += routedEventHandler;
foo.Loaded += routedEventHandler;
And then you have something like:
void button2Click(object sender, RoutedEventArgs e)
{
if (e.RoutedEvent == FrameworkElement.LoadedEvent)
{
ToolTip t = new ToolTip();
t.Content = "Something helpful";
((Button)sender).ToolTip = t;
return;
}
//Logic for handling button clicks goes here
MessageBox.Show("action 2");
}

You are not assigning the tooltip in the handler, so how should anything happen?
((Button)sender).ToolTip = t;

If I understand correctly, you want to have different "types" of buttons, each one with a different Click handler and a different Tooltip.
If that's the case, You could create different classes deriving from Button (e.g. HelpfulButton, UnhelpfulButton... choose good names please :) ) and in their constructor assign the handler and tooltip.
Then, in the main code, you could loop through the different classes and add instances of them directly to the main canvas.
Another possible option is to create different "template" buttons using commands and copy the properties from them instead of subclassing Button. Something like this:
Button helpfulTemplate = new Button { ToolTip = "blah" };
helpfulTemplate.Command = HelpfulCommand;
Button unhelpfulTemplate = new Button { ToolTip = "bloh" };
unhelpfulTemplate.Command = UnhelpfulCommand;
foreach(var template in new Button[] {helpfulTemplate, unhelpfulTemplate})
{
var newCopy = new Button();
//etc.
newCopy.ToolTip = template.ToolTip;
newCopy.Command = template.Command;
}

Related

Reflection added Delegate not firing

This is the code.
For example purposes, NewButton will have the name "Add", the SubMenuButtonNamesList is a list of strings containing the names of the buttons that I will be creating, afterwards I wanted to add the handler to these buttons based on the methods found in the mainwindow, matched by their names.
I think I did it properly since the button does have this handler added, but when I click the button nothing happens, it should show me a messagebox saying "yes".
public void Add_Method(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("Yes");
}
public MainWindow()
{
InitializeComponent();
//Create all sub-menu buttons
foreach (var element in SubMenuButtonNamesList)
{
Button NewButton = new Button()
{
Background = new SolidColorBrush(new Color { A = 100, R = 231, G = 233, B = 245 }),
FontFamily = new FontFamily("Century Gothic"),
Content = element,
FontSize = 14,
Height = 30,
Width = Double.NaN,
VerticalAlignment = VerticalAlignment.Center,
HorizontalAlignment = HorizontalAlignment.Center
};
NewButton.Name = element.Trim();
try
{
MethodInfo method = typeof(MainWindow).GetMethod(NewButton.Name + "_Method");
Delegate myDelegate = Delegate.CreateDelegate(typeof(MouseButtonEventHandler), this, method);
NewButton.MouseLeftButtonDown += (MouseButtonEventHandler)myDelegate;
}
catch (Exception e)
{
}
SubMenuButtonsList.Add(NewButton);
}
}
It appears the MouseLeftButtonDown event for Button (didn't check for anything else), if added this way will not fire, however if you do it for the Click event, it will fire properly, see below snippet of the modifications:
MethodInfo method = typeof(MainWindow).GetMethod(NewButton.Name + "_Method");
Delegate myDelegate = Delegate.CreateDelegate(typeof(RoutedEventHandler), this, method);
NewButton.Click += (RoutedEventHandler)myDelegate;
And the method:
public void Add_Method(object sender, RoutedEventArgs e)
{
MessageBox.Show("Yes");
}

I want to make a my own button which has 2 other button inside and I want to make them transparent but transparency doesn't work

I have a button, I put 2 other buttons inside it. I want those 2 other buttons to only appear when I enter the main button with my mouse. When I enter it, I want the 2 other buttons to be half opaque and only be fully opaque when I enter one of those 2 buttons.
These buttons are inside a FlowLayoutPanel with a background image on it.
This is how they look like:
The Buttons have a picture inside them and a text.
Here is my code:
public class MyButton : Button
{
public MyButton()
{
SetStyle(ControlStyles.StandardClick |
ControlStyles.StandardDoubleClick, true);
Text = component.ProductsName;
TextAlign = ContentAlignment.TopCenter;
ImageAlign = ContentAlignment.TopLeft;
Size = new Size(178, 75);
foreach (Button item in CustomButtons())
{
Controls.Add(item);
}
}
static Button[] CustomButtons()
{
Button delete = new Button();
delete.Location = new Point(157, 1);
delete.Size = new Size(20, 20);
delete.MouseEnter += OnMouseEnter;
delete.MouseLeave += DeleteOnMouseLeave;
Button customize = new Button();
customize.Location = new Point(delete.Left - 20, 1);
customize.Size = new Size(20, 20);
Button[] buttons = {delete, customize};
return buttons;
}
private static void DeleteOnMouseLeave(object sender, EventArgs e)
{
Button btn = (Button) sender;
btn.UseVisualStyleBackColor = true;
btn.BackColor = Color.Transparent;
}
private static void OnMouseEnter(object sender, EventArgs e)
{
Button btn = (Button) sender;
btn.UseVisualStyleBackColor = false;
btn.FlatAppearance.MouseOverBackColor = Color.FromArgb(100,
Color.Black);
}
}
I think I tried everything that came to my mind, I tried events and everything and the buttons never worked as I intended them to work.
Any help would be appreciated! Thanks! :D
it seems I solved it! I only had to set Flatstyle = FlatStyle.Flat and backColor = Color.Transparent! :D
Here is the result: exsample of output

Change background of a button when clicking another button

I am currently experimenting in WPF and just created a UniformGrid with 800 buttons which are created in a for loop. All buttons have their own names and share the same click event.
What I want to do now is the following: I want to click the first button (rect0) to change the color of this button and the next one (rect1).
I am totally stuck right now because everything I write into the click event refers to the button I clicked.
public MainWindow()
{
InitializeComponent();
for (int i = 0; i < 800; i++)
{
Button BTN_rect = new Button()
{
Name = "rect" + i,
Background = Brushes.White,
};
BTN_rect.Click += BTN_rect_Click;
Uniform.Children.Add(BTN_rect);
}
}
private void BTN_rect_Click(object sender, RoutedEventArgs e)
{
Button BTN_rect = sender as Button;
BTN_rect.Background = Brushes.Red;
MessageBox.Show(BTN_rect.Name);
}
There are a load of ways to do this.
I took a shortcut and put just 9 buttons in a stackpanel, otherwise the same.
public MainWindow()
{
InitializeComponent();
for (int i = 0; i < 8; i++)
{
Button BTN_rect = new Button()
{
Name = "rect" + i,
Content =Name,
Tag = i,
Background = Brushes.White,
};
BTN_rect.Click += BTN_rect_Click;
sp.Children.Add(BTN_rect);
}
}
private void BTN_rect_Click(object sender, RoutedEventArgs e)
{
Button current = sender as Button;
current.Background = Brushes.Red;
string targetName = $"rect{((int)current.Tag) + 1}";
Button nextButton = sp.Children.OfType<Button>().Where(x => x.Name == targetName).SingleOrDefault();
nextButton.Background = Brushes.Red;
}
Usually, you'd template data into repeated controls rather than add them in code, btw.

C# Programmatic created button - enable programmatically created textbox

Hoping you can help - I have programmatically created button & richtextbox.
// Button to Edit
Button butEditToDo = new Button();
butEditToDo.Location = new Point(285, 10);
butEditToDo.Size = new System.Drawing.Size(25, 25);
butEditToDo.BackColor = Color.Transparent;
butEditToDo.FlatStyle = FlatStyle.Flat;
butEditToDo.FlatAppearance.BorderSize = 0;
butEditToDo.FlatAppearance.MouseOverBackColor = Color.FromArgb(244, 244, 244);
butEditToDo.Cursor = Cursors.Hand;
butEditToDo.BackgroundImage = ((System.Drawing.Image)(Properties.Resources.Edit_25));
pnlPendingNote.Controls.Add(butEditToDo);
// Pending Nane + Tag
RichTextBox rxtNotes = new RichTextBox();
rxtNotes.Size = new System.Drawing.Size(317, 68);
rxtNotes.Location = new Point(3, 37);
rxtNotes.Text = (read["notNote"].ToString());
rxtNotes.ReadOnly = true;
rxtNotes.BorderStyle = BorderStyle.None;
rxtNotes.DetectUrls = true;
rxtNotes.BackColor = Color.FromArgb(244, 244, 244);
pnlPendingNote.Controls.Add(rxtNotes);
So when ever I click on ButEditToDo_Click - I can get the right button clicked.
So when I click on this button I would like to enable the RichTextbox - and when I click the button again - I would like to update the database.
Button Click:
private void ButEditToDo_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
for (int i = 1; i < pendingcounter; i++)
{
if (btn.Name == ("PenNote" + i))
{
break;
}
}
}
Hope you can help please with enabling the button, I'm all good with the database.
Thank you.
Edit One
#Ed - thank you.
Please See Image.
What I would like to achieve - When i click on the tools icon - the RichTextBox will be enabled.
So if I click on the tools on first panel - then the R_TextBox will be enabled for me to edit the text.
Then the Icon will change and I will be able to click on it again to save to the database.
Hope that makes more sense for you Ed.
Just give the button an event handler that does stuff. Use a lambda so you can reference the local reference to the RichTextBox.
Button butEditToDo = new Button();
// ...snip...
RichTextBox rxtNotes = new RichTextBox();
// ...snip...
butEditToDo.Click += (sender, args) =>
{
CycleNoteState(rxtNotes);
};
And here's the guts of the event handler. You could put this all in the event handler, but the code's more readable this way. CycleNoteState isn't a very good name, but I'm not clear about the semantics of your program.
I may have misunderstood the logic for what the button does on successive clicks. If it's more complicated than this, you can introduce a state enum or something. Let me know and we'll get it figured out.
private void CycleNoteState(RichTextBox rtb)
{
if (!rtb.Enabled)
{
rtb.Enabled = true;
}
else
{
// Do save stuff here
}
}

How to find out which button I pressed?

Picture the notification-dropdown menu from Facebook.
I want to implement something similar. When clicking 'Slet', it's supposed to delete that notification from the list.
private void AddNotificationsToPanel(List<Notification> notifications, StackPanel panel)
{
panel.Children.Clear();
foreach (var notification in notifications)
{
//We want every message to have text, a delete button and a postpone button
//So we need a nested stackpanel:
var horizontalStackPanel = new StackPanel();
horizontalStackPanel.Orientation = Orientation.Horizontal;
panel.Children.Add(horizontalStackPanel);
//Display the message:
var text = new TextBlock();
text.Text = notification.Message;
text.Foreground = Brushes.Black;
text.Background = Brushes.White;
text.FontSize = 24;
horizontalStackPanel.Children.Add(text);
//Add a delete button:
var del = new Button();
del.Content = "Slet";
del.FontSize = 24;
del.Command = DeleteNotificationCommand;
horizontalStackPanel.Children.Add(del);
//Add a postpone button:
var postpone = new Button();
postpone.Content = "Udskyd";
postpone.FontSize = 24;
postpone.IsEnabled = false;
horizontalStackPanel.Children.Add(postpone);
}
panel.Children.Add(new Button { Content = "Luk", FontSize = 24, Command = ClosePopupCommand });
}
Basically, I have a vertical stackpanel with x amount of horizontal stackpanels. Each of those have a textbox and two buttons.
How do I know which button I clicked? The buttons are all bound to a delete command, but I'm kind of unsure how these work:
public ICommand DeleteNotificationCommand
{
get{
return new RelayCommand(o => DeleteNotification());
}
}
Which then create this method:
private void DeleteNotification()
{
Notifications.Remove(NotificationForDeletion);
AddNotificationsToPanel(Notifications, Panel);
}
Problem is we don't know which Notification to delete, because I don't know how to see which button was clicked. Any ideas?
You should use CommandParameter property of the button by assigning unique identifier of each notification to it. I'm assuming your notification has an unique integer id:
//Add a delete button:
var del = new Button();
del.Content = "Slet";
del.FontSize = 24;
del.Command = DeleteNotificationCommand;
del.CommandParameter = notification.Id; // <-- unique id
horizontalStackPanel.Children.Add(del);
Then in the DeleteNotification method, you need to specify a parameter for the key.
public ICommand DeleteNotificationCommand
{
get{
return new RelayCommand(DeleteNotification);
}
}
private void DeleteNotification(object parameter)
{
int notificationId = (int)parameter;
var NotificationForDeletion = ...; // <--- Get notification by id
Notifications.Remove(NotificationForDeletion);
AddNotificationsToPanel(Notifications, Panel);
}
Now, in the DeleteNotification you can identify the Notification that is related to the button.

Categories

Resources