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");
}
Related
private void createCarers()
{
foreach (Carer c in CarerManager.Carers.Values)
{
Button x = new Button
{
Content = c.name,
MinHeight = 50,
Tag = c,
Margin = new Thickness(0, 0, 0, 10)
};
x.Click += new RoutedEventHandler(carerClick);
carersPanel.Children.Add(x);
}
}
private void carerClick(object sender, RoutedEventArgs e)
{
System.Windows.Application.Current.Shutdown();
}
Ok so createCarers is called when the window is initialised.
Why does this not work? The shutdown thing is just a test but it does not work.
I'm using c#, and I have a project that instantiates a lot of PictureBox buttons. I also have all of the click,hover,mouseUp,mouseDown event methods programmed. How do I call a method from a string name so that I don't have to write all of them by hand? Thanks in advance, Carson
Dictionary<string, PictureBox> buttonList = new Dictionary<string,PictureBox>();
string buttonName = "button_file";
buttonList[buttonName].Click += new EventHandler(buttonName + "_click");
public void button_file_click(object sender, EventArgs e)
{
// do on click stuff here
}
if you set the Name property of button, you can so:
buttonList[buttonName].Name = buttonName;
buttonList[buttonName].Click += ButtonClick;
and only One metode hanle all buttons click but in accordance of their name:
public void ButtonClick(object sender, EventArgs e)
{
var btn = (Button)sender;
btn.Text = btn.Name; //only for demo
}
but you can completely write your own method:
buttonList[buttonName].Click += (s,e)=> clickEvent(buttonList[buttonName], buttonName);
this is a short lambda function which accepts the parameters accordingly of Click event singature and fire your custom function, the clickEvent:
public void clickEvent(Button thePressedButton, string nameOfPresedButton)
{
thePressedButton.Text = btn.nameOfPresedButton; //only for demo
}
From your sample code, I assume you want them all to call button_file_click.
In that case just set the eventhandler to that method:
buttonList[buttonName].Click += new EventHandler("button_file_click");
A method name isn't quite enough... you also need a class name... but assuming the method belongs to the current class (this) you can use Reflection to do this:
public void ExecuteMethod(string methodName)
{
var methodInfo = this.GetType().GetMethod(methodName);
methodInfo.Invoke(this, new [] {});
}
But you can't assign the above to an event because it is not the right delegate type; most event handlers require a sender and an EventArgs. So to make your code work you'd need a little more glue:
Dictionary<string, PictureBox> buttonList = new Dictionary<string,PictureBox>();
string buttonName = "button_file";
buttonList[buttonName].Click += GetHandler(buttonName + "_click");
public Action<object, EventArgs> GetHandler(string handlerName)
{
var methodInfo = this.GetType().GetMethod(handlerName, new Type[] {typeof(object), typeof(EventArgs)});
return new Action<object, EventArgs> (sender, eventArgs) => methodInfo.Invoke(this, new [] {sender, eventArgs});
}
The idea here is that GetHandler returns an Action with the right signature (accepting an object and an EventArgs, in that order), which is written as Action<object, EventArgs>. The GetHandler method uses reflection to find the right method in the current class, then creates a lambda expression that invokes the method via reflection, passing the arguments as an array.
The above is of course just an example... it would probably be better to store your delegates in a static dictionary that is computed when the page is loaded for the first time.
That being said, if you're looking for event handling flexibility based on a runtime parameter, a better approach is probably to use the Command event, which allows you to pass a string to the handler, which can then take a different action depending on the contents of the string. That way you can hardcode the handler reference but still softcode what it will do.
Dictionary<string, PictureBox> buttonList = new Dictionary<string,PictureBox>();
string buttonName = "button_file";
buttonList[buttonName].Command += buttonList_Command;
buttonList[buttonName].CommandName = buttonName;
protected void buttonList_Command(object sender, CommandEventArgs e)
{
switch (e.CommandName)
{
case buttonName:
//Do stuff for button_file
break;
case "Foo":
//Do stuff for some other button named foo
break;
default:
throw new InvalidOperationException();
}
}
You can use reflection to look up the method of a class by name and then create an event handler delegate using that method. For example:
void bindHandler(string buttonName)
{
string methodName = buttonName + "_click";
System.Reflection.MethodInfo m = this.GetType().GetMethods().FirstOrDefault(x => x.Name == buttonName + "_click");
PictureBox button = buttonList[buttonName];
Delegate handler = Delegate.CreateDelegate(typeof(EventHandler), this, m);
button.Click += (EventHandler)handler;
}
Fulling working code:
namespace WindowsFormsApp1Cs
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
MyClass c = new MyClass();
foreach (var item in c.buttonList)
{
this.Controls.Add(item.Value);
}
}
}
public class MyClass
{
public Dictionary<string, PictureBox> buttonList;
public delegate void MyClickHandler(object sender, EventArgs e);
public MyClass()
{
buttonList = new Dictionary<string, PictureBox>();
buttonList.Add("button_file_1", new PictureBox() { Width = 100, Height = 100, Name = "button_file_1", Anchor = AnchorStyles.Top | AnchorStyles.Left, Top = (buttonList.Count * 100) + 10, Left = 10, ImageLocation="0.jpg" });
buttonList.Add("button_file_2", new PictureBox() { Width = 100, Height = 100, Name = "button_file_2", Anchor = AnchorStyles.Top | AnchorStyles.Left, Top = (buttonList.Count * 100) + 10, Left = 10, ImageLocation = "0.jpg" });
buttonList.Add("button_file_3", new PictureBox() { Width = 100, Height = 100, Name = "button_file_3", Anchor = AnchorStyles.Top | AnchorStyles.Left, Top = (buttonList.Count * 100) + 10, Left = 10, ImageLocation = "0.jpg" });
foreach (var item in buttonList)
{
bindHandler(item.Key);
}
}
void bindHandler(string buttonName)
{
string methodName = buttonName + "_click";
System.Reflection.MethodInfo m = this.GetType().GetMethods().FirstOrDefault(x => x.Name == buttonName + "_click");
PictureBox button = buttonList[buttonName];
Delegate handler = Delegate.CreateDelegate(typeof(EventHandler), this, m);
button.Click += (EventHandler)handler;
}
public void button_file_1_click(object sender, EventArgs e)
{
Debug.WriteLine("button_file_1_click");
}
public void button_file_2_click(object sender, EventArgs e)
{
Debug.WriteLine("button_file_2_click");
}
public void button_file_3_click(object sender, EventArgs e)
{
Debug.WriteLine("button_file_3_click");
}
}
}
When I click a button I want to delete that particular flowlayout panel along with the check box and the button itself.But I have no clue how to do this.
Here is my code to do this:
private static CheckBox _taskCompletionCheckBox;
public static void DisplaySingleTask(LayoutType layoutType, FlowLayoutPanel layoutPanel,TodoItem item)
{
//creates a panel
var parentPanel = new FlowLayoutPanel {Parent = layoutPanel, AutoSize = true, BorderStyle = BorderStyle.FixedSingle};
//Based on layout type, the panel's content's are determined
switch (layoutType)
{
case LayoutType.Small:
_taskCompletionCheckBox = new CheckBox {Parent = parentPanel, Dock = DockStyle.Left,Text = item.Name,AutoSize = true,BackColor = Color.Transparent};
_taskCompletionCheckBox.CheckedChanged += checkBox_CheckedChanged;
_taskCompletionCheckBox.Show();
var delBtn = new Button { Parent = parentPanel, Dock = DockStyle.Left, Size = new Size(30, _taskCompletionCheckBox.Size.Width),Image = Resources.DeleteTaskImage};
delBtn.Click += delBtn_Click;
break;
case LayoutType.Normal:
break;
case LayoutType.Full:
break;
default:
throw new ArgumentOutOfRangeException("layoutType");
}
}
static void delBtn_Click(object sender, EventArgs e)
{
//I would like to know how can I get a reference to the the flowlayout panel here so I can call the dispose() method on it.
}
If I have got your point, the FlawLayoutPanel you are looking for is parent of the button. Cast the sender parameter of the event handler to button and get it's parent.
static void delBtn_Click(object sender, EventArgs e)
{
Button button = (Button)sender;
FlowLayoutPanel panel = (FlowLayoutPanel)button.Parent;
// ..
}
3 problems in my WPF(window phone) simple project. I have spent lot of time by solving it but no specific result found..
In my cs file I have Created bunch of dynamic buttons...I crated with for loop and set tags for each dynamic button.
My cs File code is here.
private void Grid_View_Btn_1_Click(object sender, System.Windows.RoutedEventArgs e)
{
//Grid ButtonsAddition
Dispatcher.BeginInvoke(() =>
{
string[] Trade = new string[] { "Portfolio Display", "Trade Idea Entry", "Trade Idea Monitor", "Historical Performance", "Intraday Performance", "Stock Performance" };
StackPanel panel = new StackPanel();
panel.Orientation = System.Windows.Controls.Orientation.Vertical;
//panel.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
//panel.VerticalAlignment = System.Windows.VerticalAlignment.Top;
int i;
for (i = 0; i < Trade.Length; i++)
{
Button btn = new Button() { Content = Trade[i] };
btn.Margin = new Thickness(0, -10, 0, -10);
var brush = new ImageBrush();
brush.ImageSource = new BitmapImage(new Uri("C:/Users/HafizArslan/Documents/Visual Studio 2012/Projects/AimPass/AimPass/Images/tabbar_btn_blue.png", UriKind.Relative));
btn.Background = brush;
btn.Width = 190;
btn.Height = 75;
btn.FontSize = 14;
btn.FontWeight = light;
btn.FontStretch = Fill;
btn.HorizontalAlignment = HorizontalAlignment.Center;
btn.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
// btn.CornerRadius = new CornerRadius(15);
btn.BorderThickness = new Thickness(1, 1, 1, 1);
btn.Tag = i.ToString();
btn.Click += new RoutedEventHandler(abc_click);
panel.Children.Add(btn);
}
grid.Children.Add(panel);
});
}
private void abc_click(object sender, EventArgs e)
{
}
There are 6 buttons creted.
the problem is I want to perform different actions with button...I have set Tags but I dont know how can I access an actions with buttons Tag..?
I mean I want something like this...!!
private void abc_click(object sender, EventArgs e)
{
// If(btn.Tag==1)
{
//Some Code Here
}
else
if(btn.Tag==2) {
//Perform other Function
}
} Etc.....?
and other problem is I have made a image brush..Assign exact path of image...for every created button background....But Image is not attached...
Kindly tell me about these 2 problems...
You have sender in handler, you can type cast sender to button and access Tag property from it:
private void abc_click(object sender, EventArgs e)
{
Button button = (Button)sender;
if(Convert.ToInt32(button.Tag) == 1)
{
.....
}
}
In your for loop, you can associate handler to the button.
Such as:
Button btn = new Button() { Content = Trade[i] };
btn.Margin = new Thickness(0, -10, 0, -10);
if(<something>)
btn.Click += YourEventHandler1;
if(<something2>)
btn.Click += YourEventHandler2;
If you want to access tag property, you need to cast the sender to Button, as so:
private void abc_click(object sender, EventArgs e)
{
var btn = (Button)sender;
}
you should go with this
var tag=((sender as Button).Tag).ToString();
////now use a switch
Switch(tag)
{
case "1":
//Action
break;
case "2":
//Acrion
break;
//more cases
}
hope this helps.
if for all created buttons the event is same then One approach could be to get the tag in the event like this
int tag=Convert.ToInt32((sender as Button).Tag);
now use a switch
switch(tag)
{
case 1:
//Action
break;
case 2:
//Acrion
break;
//more cases
}
hope this helps.
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;
}