howto pass dictionary key in a form event C#? - c#

Here is the code that I am running:
private Dictionary<string, List<GuiEvent>> m_events = new Dictionary<string, List<GuiEvent>>();
private void OnRadioBtnCheckedChange(object sender, EventArgs e, string formhandle)
{
RadioButton control = (RadioButton)sender;
GuiEvent evnt = new GuiEvent
{
id = GuiEventType.RadioButtonChange,
ElementName = control.Name,
sparam = control.Text,
lparam = control.Checked ? 1 : 0
};
m_events[formhandle].Add(evnt);
}
Getting the error:
Severity Code Description Project File Line Suppression State
Error CS0123 No overload for 'OnRadioBtnCheckedChange' matches delegate 'EventHandler' MtGuiController C:\Users\AIMS-RESEARCH\Desktop\MtGuiController\MtGuiController\Controller.cs 258 Active
Previously when the m_event was declared like this:
private List<GuiEvent> m_events = null;
And the function:
private void OnRadioBtnCheckedChange(object sender, EventArgs e)
{
RadioButton control = (RadioButton)sender;
GuiEvent evnt = new GuiEvent
{
id = GuiEventType.RadioButtonChange,
ElementName = control.Name,
sparam = control.Text,
lparam = control.Checked ? 1 : 0
};
m_events.Add(evnt);
}
Everything was working fine.
I am not able to understand what I can do in this situation. I cannot declare string formhandle as global as it is changing every time. So please take a note of it. It is C# DLL function.
Can anybody tell me solution that will help?

If you want to use some additional information in your event handler, you cannot pass it as an additional parameter to event handling function. You cannot also change type of event handler parameters - it should just accept two arguments - sender and EventArgs.
You have three options here. First - store data in sender and then access that data in event handler. Simplest way is using radio button's tag. Control.Tag is inherited from base Control class and you can use it to store some data when you create control. I.e. assign appropriate formhandle to every radio button Tag (you can even do that manually via designer)
radioButton1.Tag = "foo";
radioButton2.Tag = "bar";
and then retrieve it in event handler:
private void OnRadioBtnCheckedChange(object sender, EventArgs e)
{
RadioButton control = (RadioButton)sender;
GuiEvent evnt = new GuiEvent
{
id = GuiEventType.RadioButtonChange,
ElementName = control.Name,
sparam = control.Text,
lparam = control.Checked ? 1 : 0
};
var formhandle = (string)control.Tag; // here you get "foo" or "bar"
m_events[formhandle].Add(evnt);
}
Second option - create your custom radio button control. But that's overkill here. Usually, you do that when you need a custom look & feel, not just to pass data.
Third option - lookup data you want using the data you have (e.g. control name). This option makes sense when data you need is not available at the time of control creation or if it changes over time.

Related

Adding properties to be used in XAML dynamically

is it possible to add dynamic properties to be used in a different class? I mean for example I created a "Leave feedback" button, and when I click it, I want it to send the name of that person to the server. And I want to put the name of those persons when I define those buttons, like:
private void LeaveFeedback(object sender, EventArgs e) {
Button btn = sender as Button;
// I actually do not know how to access that property as well.
// Maybe something like a dictionary to specify the dynamic properties as `PropertyName: PropertyValue` pair would be efficient.
}
<Button Click="LeaveFeedback" FeedbackPerson="some_person" UserID="some_person_id" .../>
<Button Click="LeaveFeedback" FeedbackPerson="some_person_2" UserID="some_person_2_id" .../>
and so on.
How can I do that? Should I declare a specific control?
You could set the Tag property to an instance of a custom or anonymous type:
Button btn = sender as Button;
btn.Tag = new { FeedbackPerson = "some_person", UserID = "some_person_id" };
Retrieval is flexible but untyped and fragile:
dynamic tag = btn.Tag;
string feedbackPerson = tag.FeedbackPerson.ToString();
string iserID = tag.UserID.ToString();
A more elegant solution would be create two attached properties that you can set and get like this:
Behavior.SetFeedbackPerson(btn, "some_person");
string feedbackPerson = Behavior.GetFeedbackPerson(btn);

Having a reference to a property, Is there a way to grab a reference to the encompassing object?

I have extended the Label class as follows:
public class MyLabel: Label {
public Button btn;
public string mydata;
}
In my main program, I instantiated a new instance:
MyLabel lbl = new MyLabel();
lbl.mydata = "some data here";
lbl.btn = new Button();
lbl.btn.Click += new EventHandler(button_pressed);
this.Controls.Add(lbl); // Adds the label to the form
this.Controls.Add(lbl.btn); // Adds the button to the form
And I created a method to handle the button click event:
void button_pressed(Object sender, EventArgs e) {
Button btn = (Button)sender;
//Now I have an access to the property within MyLabel instance.
// but how can I access the parent object?
// I need to access the sibling property [mydata] string from here
btn.Siblings["mydata"] = "some other thing" ; //Something like this
MyLabel lbl = btn.ParentObject(); //Or something like this
lbl.mydata = "Some other thing";
}
This looks like WinForms, in which case either a UserControl or extending Button class might be a good way to go - just maintain a reference to the parent (a bit more complicated with UserControl, you'd need to define the click event on that control, otherwise you're back to "square 1") I like the Tag property solution as well, although there is an additional cast, and no guarantee of type safety (since Tag is an object, it can be anything by the time you try to access it).
However, let's say you're looking for a more general solution; let's also say that the class in question is sealed, has no Tag or similar purpose property, and a Controls collection is not available (or looping through it is not desirable for performance reasons). To my best knowledge, you can't determine parent object; but you can easily provide your own "Controls" style dictionary, mapping the Button to the parent:
public class MyLabel: Label {
public static Dictionary<Button, MyLabel> ParentMap = new Dictionary<Button, MyLabel>();
public Button btn;
public string mydata;
public void AddToParentMap() => ParentMap[btn] = this;
}
When you're creating an instance of MyLabel, just call the AddToParentMap() function (can't be done in constructor, because this pointer is not available until the object is created):
MyLabel lbl = new MyLabel();
lbl.AddToParentMap();
You can then just look it up, fast and easy, in your click event:
void button_pressed(Object sender, EventArgs e) {
Button btn = (Button)sender;
var label = MyLabel.ParentMap[btn];
//...
//Your code...
}
Unlike the Tag solution, type safety is guaranteed - you always know you're accessing a MyLabel object.
You can't access it through button instance but what you can do is to get MyLabel from Controls collection:
var lbl = this.Controls.OfType<MyLabel>().FirstOrDefault(c => c.btn == btn);
You can use the Tag property.
lbl.btn = new Button();
lbl.btn.Tag = lbl;
And then when you need it:
Button btn = (Button)sender;
Label lbl = (MyLabel)btn.Tag;

Control changing control on other UserControl

I have a User Control that contains a combobox/drop down list. This user control is used multiple times and added dynamically to a panel. When I change the value of the combobox on one user control, it changes the rest? Does anyone know how to sort this?
So to clarify. When I change the value in the combobox of the top usercontrol (7002), it will change the second user controls combobox value to whatever I selected.
Thanks!
Code for adding the controls;
foreach (Common.UserDTO UDTO in BLL.User.GetAllUsers())
{
Admin_UserControls.UserBar UB = new Admin_UserControls.UserBar(UDTO);
UB.Location = new Point(0, int.Equals(pnlUserBlock.Controls.Count, 0) ? 0 : pnlUserBlock.Controls[pnlUserBlock.Controls.Count - 1].Bottom);
pnlUserBlock.Controls.Add(UB);
}
constructor/load events:
private Common.UserDTO UDTO;
public UserBar(Common.UserDTO UDTO)
{
InitializeComponent();
/* Store the passed in UserDTO */
this.UDTO = UDTO;
}
private void UserBar_Load(object sender, EventArgs e)
{
/* Setup the Drop down list */
cbRanks.DataSource = Common.Helper.GetRanksDT();
cbRanks.DisplayMember = "Rank";
cbRanks.ValueMember = "ID";
/* Setup the users */
lblUsername.Text = UDTO.Username;
cbRanks.SelectedValue = UDTO.RankID;
}
Put the above comment into an answer should others have the same issue in future.
Each instance of the UserControl that is created is bound to the same DataSet giving you this result.
Caused by the line:
cbRanks.DataSource = Common.Helper.GetRanksDT();
To resolve this simply declare a new instance each time the UserControl is created, see this post that discusses a few methods.

Reading __EVENTTARGET causes event is not called

I want to use information on which control was clicked for setting up the page. I use this to set up a sortable table in code. I found through this forum that I can use Request.Form.Get("__EVENTTARGET") for that. However, as soon as I do something with that parameter, the callback function is no longer called. Is this expected behavior or am I making a mistake?
Here some snippets of my code. The code in Page_Load() is:
string sortRequest = Request.Form.Get("__EVENTTARGET");
bool isCurrentField = false;
if (sortRequest != null) isCurrentField = sortRequest.Contains(header.Field);
if (!isCurrentField)
{
// Add a hyperlink for sorting to the cell
LinkButton newLink = new LinkButton();
newLink.Text = header.Title;
newLink.Font.Bold = true;
newLink.ID = "link" + header.Field;
newLink.CommandName = "Sort";
newLink.CommandArgument = header.Field;
newLink.Command += new CommandEventHandler(LinkButton_Command);
hdrCell.Controls.Add(newLink);
}
else
{
hdrCell.Text = header.Title;
hdrCell.Font.Bold = true;
}
My callback:
public void LinkButton_Command(Object sender, CommandEventArgs e)
{
_sortOrder = e.CommandArgument.ToString();
}
I have also tried it with copying the sortRequest into a temporary variable, but that doesn't make a difference. As soon as I comment out the line if (sortRequest != null) isCurrentField = sortRequest.Contains(header.Field);, the callback is called again.
There is a fault in your logic. You have a dynamically created control LinkButton with LinkButton_Command event handler connected to it. For the server-side event to fire on postback, the control must be present in the page control tree. This means the dynamic LinkButton must be created, configured and added to hdrCell.Controls always, regardless of sortRequest value. Only then will it be able to pick up the fact that it was clicked from the Request and fire its Command event.

TreeView Event keeps firing

I'm using the WPF version of TreeView (System.Windows.Controls.TreeView) and need to assign several events. As these are WPF most of the events are either different or behave in a different way hence my confusion as AfterExpand is not available
For now I need 2 events:
SelectedItemChanged which is at TreeView level
ExpandedEvent which is at TreeViewItem level
So far I have
private void DisplayGetEventTypes(UXEvent.GetEventTypesResp resp, CustomAsyncStateContainer state)
{
navBarControl.Groups.Clear();
if (resp.eventTypeItems != null)
{
UXEvent.EventType[] eventItems = resp.eventTypeItems;
int nodeCount = eventItems.Length;
for (int i = 0; i < nodeCount; i++)
{
UXEvent.TryEvent eventItem = new UXEvent.TryEvent();
eventItem.eventName = eventItems[i].name;
eventItem.eventId = eventItems[i].id;
NavBarGroup group1 = new NavBarGroup();
group1.Header = eventItems[i].name;
group1.Tag = eventItem;
group1.IsExpanded = false;
//Add dummy treeview to fill later if expanded
System.Windows.Controls.TreeView treeview = new System.Windows.Controls.TreeView();
treeview.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(myTreeView_SelectedItemChanged);
AddHandler(TreeViewItem.ExpandedEvent, new RoutedEventHandler(myTreeView_ItemExpanded));
group1.Content = treeview;
group1.DisplaySource = DisplaySource.Content;
navBarControl.Groups.Add(group1);
}
}
}
and the following two draft event handlers for testing
void myTreeView_SelectedItemChanged(object sender,
RoutedPropertyChangedEventArgs<object> e)
{
// Set the data context of the text block to the selected value.
var node = (ItemsControl)e.OriginalSource;
System.Windows.Forms.MessageBox.Show("Selected!");
}
void myTreeView_ItemExpanded(object sender, RoutedEventArgs e)
{
// Set the data context of the text block to the selected value.
var node = (TreeViewItem)e.OriginalSource;
System.Windows.Forms.MessageBox.Show("Opening! - " + node.Header);
}
The problem I'm having is that myTreeView_ItemExpanded is firing multiple times when any treeviewItem is expanded. I think it fires multiple times due to the event bubbling .
Firstly, can anyone point me to some good resources where I can read up on this behaviour?
Secondly, how can I amend my code to make AddHandler(TreeViewItem.ExpandedEvent, new RoutedEventHandler(myTreeView_ItemExpanded)); a single event only?
Thank you
I spotted the problem. The line
AddHandler(TreeViewItem.ExpandedEvent, new RoutedEventHandler(myTreeView_ItemExpanded));
should read
treeview.AddHandler(TreeViewItem.ExpandedEvent, new RoutedEventHandler(myTreeView_ItemExpanded));
I assume the first line must have added the event handler to all available controls and all fired when the event triggered.

Categories

Resources