I am currently trying to add to a context menu strip a dictionary of status values. The main issue I am having is how to pass in the Key value of the selected dictionary item to a click event.
Dictionary<int, string> statusList = getStatusList();
if (statusList.Count > 0)
{
Dictionary<int, ToolStripItem> statusMenu = new Dictionary<int, ToolStripItem>();
foreach (var keyValuePair in statusList)
{
statusMenu.Add(keyValuePair.Key, new ToolStripMenuItem() { Text = keyValuePair.Value.ToString(), Image = Resources.Refresh });
//statusMenu[statusMenu.Count - 1, statusMenu].Click += new EventHandler(MenuOption_Click_Handler); This is where I am confused
}
datagridview1.ContextMenuStrip.Items.Add(new ToolStripMenuItem("Set Status to", Resources.Refresh, statusMenu.Values.ToArray()));
}
I can easily get the array of the dictionary values. I am just wondering if its possible upon clicking a status in the contextmenu to pass the Key to a save method?
So, for example say statusList contains the following values:
{[1, Status1]}
{[2, Status2]}
{[5, Status3]}
So if I load the contextmenu, if I click Status3, I need to pass to the ClickEvent that Status Key 5 was clicked. Right now its only detecting the Value (Status3). Any help is much appreciated!
Why don't you rename your tooltip control? The id is the key of Dictionary, so it should be distinct. Anyway, any control must have name.
This is an idea. You name the control with the prefix ToolStrip(or whatever you like) + Key and get it later. Like:
var newItem= new ToolStripMenuItem() {
Text = keyValuePair.Value.ToString(),
Image = Resources.Refresh,
Name="ToolStrip" + keyValuePair.Key };
newItem.Click +=new EventHandler(MenuOption_Click_Handler);
statusMenu.Add(keyValuePair.Key,newItem);
In MenuOption_Click_Handler method:
public void MenuOption_Click_Handler(object sender,EventArgs e)
{
var id = Convert.ToInt32(((ToolStripMenuItem)sender).Name.Substring(0,9));
}
Related
I am making a mobile app using Xamarin Forms and I am writing all of my code including the visual aspects in c# (in the .cs files).
Essentially I need to be able to add a new entry every time a button is pressed and then get the text entered into said entry.
Right now I can create a new Entry and give it a name that I can use to reference it:
private Entry entry1;
Layout.Children.Add(entry1 = new Entry
{
//entry code
});
//when some button is pressed
string entry1Text = entry1.Text;
I want to make it so that every time the user presses a button, it creates a new entry, but I also need to be able to get the text from it. How can I make it so that it creates a new entry with a new name like entry2, entry3, etc... without manually writing out like 10 entries and then making them visible? I need to do this because I don't know how many entries the user will add (could be more than 10).
int numberOfEntries = 1;
void addEntry_Clicked(object sender, EventArgs e)
{
string entryNumber = numberOfEntries.ToString();
//the following 2 lines are what doesn't work with the name of an entry, but is what I want to do
private Entry entry + entryNumber;
Layout.Children.Add(entry + entryNumber = new Entry
{
//entry code
});
numberOfEntries+=1;
}
//some button is pressed
string entryText = (entry + entryNumber).Text;
The problem is I can't add a number to the name of an entry like entry +"2"
Is this even possible for me to do?
you need to keep a separate data structure to track your controls, like this
Dictionary<string,Entry> entries = new Dictionary<string,Entry>();
private void AddEntry(string name)
{
var entry = new Entry();
myLayout.Children.Add(entry);
entries.Add(name,entry);
}
then you can get their value like this
var text = entries["entryA"].Text;
The goal is for the while-loop to search for new users (items) all the time and once it has found someone it gets added into the list and my stacklayout. I get all of the rows in DB just fine, the problem is that the items it finds gets added but then it keeps getting readded so i get multiple Buttons with the same values. The query is always returning all rows so it has something to do with that but I am not sure how to work around it when something is already added.
Right now with my current code it correctly adds the ones each 3000 milisec it founds but the current problem that I have is that it keeps adding them again and again even if they have been there before.
I need to prevent that and only make so it adds an item one time. This is my code:
To show you guys an example how it looks right now:
ID 1, ID 2....
after 3000 milisec...
ID 1, ID 2....
and it keeps adding the same values that has alrdy been posted.
public List<Tuple<string>> applicantList = new List<Tuple<string>> ();
async void loadActiveAnimation ()
{
while (true) {
await Task.Delay (3000);
var seeHowMany = await phpApi.getInfo ();
if ((seeHowMany ["results"] as JArray).Count > 0) {
foreach (var items in seeHowMany ["results"]) {
applicantList.Add (
Tuple.Create(
items ["id"].ToString ()
)
);
foreach (var values in applicantList) {
var button = new Button ();
button.Text = values.Item1;
myStackLayout.Children.Add (button);
}
}
}
}
}
Your problem is here:
foreach (var items in searchApplicants ["results"]) {
theId = items ["applicantId"].ToString ();
// loadProfiles should be here to load the current ID before changing.
}
loadProfiles ();
Your loop assigns all the value returned by searchApplicants[] in turn to theId and then invokes loadProfiles() so only the last one gets processed.
I would also reduce the scope of theId and make it a local variable to pass to loadProfiles() which would have made the problem clearer.
If the implementation searchApplicants[] returns you a different collection every time then you shouldn't have any duplicate.
If I'm not missing the obvious:
after:
var seeHowMany = await phpApi.getInfo ();
Clear the applicantList List (applicantList.Clear();)
If you want the buttons to reset too, then clear myStackLayout.Children.
This basically would check the database (or whatever) every 3 seconds, get the list of applicants, clear the current list, fill the list, clear the buttons, create the buttons from the current list of applicants, then do the same again after 3 seconds...
Something like this perhaps?
async void loadProfiles ()
{
var getTheInfo = await phpApi.getProfileFromID (theId); //i gather the rest of the info connected with the correct ID.
// store only newly added images this cycle
List<Tuple<string, string>> newImages = new List<Tuple<string, string>>();
foreach (var item in getTheInfo["results"]) /i loop the correct info out from the ID
{
// append to newImages instead of imagesList
newImages.Add (
Tuple.Create(
item ["Photo"].ToString (),
item ["Name"].ToString ()
)
);
}
// loop through newImages instead of imagesList
foreach (var img in newImages ) {
var inner = new StackLayout ();
var image = new CircleImage ();
image.Source = img.Item1;
var button = new Button ();
button.Text = img.Item2;
inner.Children.Add (image);
inner.Children.Add (button);
myStackLayout.Children.Add (inner);
}
// add newImages to imagesList
imagesList.AddRange(newImages);
}
So I am creating a treeview selector with C#/GTKSharp. I have the basic tree view selector functionality working: The data is loaded into my model and I can click on a node to collapse/expand.
The part I can't work out is how to tell the cell renderer to display the collapse/expand toggle button. In the examples it appears as a triangle that points right or down depending on whether the node is opened or collapsed. I just have a blank space that works as expected as I click but shows nothing.
One possibility is that I have a white on white text issue but I doubt it as my labels show up fine and I have not done any formatting yet.
I tried adding code for ShowExpanders but that was already true.
TreeView = new Gtk.TreeView();
// We add the event handlers (i.e. the control part) to the tree
TreeView.RowActivated += SelectorActivated; //On double click
TreeView.Selection.Changed += SelectorSelected; // On select (single click)
// Raise a context menu here??
// Connect to the ButtonPressEvent
// Raise a popup button
// Create columns [View]
Gtk.TreeViewColumn TreeViewColumTitle = new Gtk.TreeViewColumn();
TreeViewColumTitle.Title = "Profile";
Gtk.CellRendererText NameCellTitle = new Gtk.CellRendererText();
TreeViewColumTitle.PackStart(NameCellTitle, true);
TreeViewColumTitle.SetCellDataFunc(NameCellTitle, new Gtk.TreeCellDataFunc(RenderTitle));
NameCellTitle.Mode = CellRendererMode.Activatable;
// Populate the model
// Note that we could dispense with this step if we generated an ITreeModel
// interface in the Object class.
BindModel(Model);
// Attach everything to the pane
TreeView.Model = GTKModel;
TreeView.AppendColumn(TreeViewColumTitle);
TreeView.ShowExpanders = true;
TreeView.ExpanderColumn.Visible = true;
...
private void BindModel(Model Model) {
GTKModel = new Gtk.TreeStore(typeof(Object));
foreach (Object Object in Model.Selector) {
var BindingData = new BindingDataGTK(this, Object);
BindingData.Iter = GTKModel.AppendValues(Object);
Object.BindingData = BindingData;
BindChildren(GTKModel, BindingData);
}
}
private void BindChildren(TreeStore TreeStore, BindingDataGTK ObjectBinding) {
foreach (var Child in ObjectBinding.Object) {
var BindingData = new BindingDataGTK(this, Child);
BindingData.Iter = TreeStore.AppendValues(ObjectBinding.Iter, Child);
Child.BindingData = BindingData;
BindChildren(TreeStore, BindingData);
}
}
private void RenderTitle(Gtk.TreeViewColumn Column, Gtk.CellRenderer Cell,
Gtk.ITreeModel GTKModel, Gtk.TreeIter Iter) {
Object Object = (Object)GTKModel.GetValue(Iter, 0);
(Cell as Gtk.CellRendererText).Text = Object.Title;
Console.WriteLine("Render {0}", Object.Title);
}
So far as I know this is pretty much an automatic feature, I don't think anything special is needed to make it happen (I've certainly never needed to). You might want to try using a TreeIter to construct your tree instead?
E.g. assuming you already have a TreeView on your form with 0 (zero) columns in it called "treeview" and a list of "MyObject"s called "myListOfObjects"...
treeview.AppendColumn ("Some Title", new CellRendererText(), "text", 0);
Gtk.TreeStore _ts = new TreeStore (typeof(string));
foreach (IMyObject _mo in myListOfObjects) {
Gtk.TreeIter _it = _ts.AppendValues (_mo.SomeText);
RecurseInto (_ts, _it, _mo);
}
treeview.Model = _ts;
...
void RescureInto(Gtk.TreeStore ts, Gtk.TreeIter it, IMyObject mo)
{
foreach (IMyObject _child_mo in mo.Children) {
Gtk.TreeIter _it = ts.AppendValues (it, _child_mo.SomeText);
RecurseInto (ts, _it, _child_mo);
}
}
In theory this should work fine.
I'm reading 2 values from an INI File: The Section Name, & The value of the key named "Path"
[Game Name]
Path=C:\Game\Game.exe
What i'm trying to do is create a Context Menu Item with the caption being the Section "Game Name" and have it launch the application from the value of the "Path" key. I haven't worked much with dynamically created controls in the past, so i'm wondering if there's an easy way to create it, and assign a single line of code to it to launch the application.
Is it possible, or is there an easier way of going about it?
foreach (string SecHead in SectionHeader)
{
string[] Entry = myINI.GetEntryNames(SecHead);
if (Entry != null)
{
foreach (string EntName in Entry)
{
ArrayList row = new ArrayList();
row.Add(SecHead);
row.Add(myINI.GetEntryValue(SecHead, EntName));
DGV.Rows.Add(row.ToArray());
string filePath = Convert.ToString(myINI.GetEntryValue(SecHead, EntName));
//Create ContextMenu Entry from Data Above
Icon newIcon = Icon.ExtractAssociatedIcon(filePath);
}
}
}
I'll assume you know how to read the INI values and that they are in String variables. Let's also assume you are doing this in an event handler that supplies mouse coordinates, such as a MouseUp event:
var section = "section";
var gameExe = "c:\\somepath\\mygame.exe";
var menu = new ContextMenu();
var item = new MenuItem(section);
item.Click += (s, args) => { Process.Start(gameExe); };
menu.Items.Add(item);
menu.Show(this, new Point(e.X, e.Y));
Not tested live, but this should give you the general idea.
I am new to C# so please fogive my newbie question.
I created a dictionary of controls from a Windows form called dictControls. I then populated it with all text box and combobox controls and values from the form:
Dictionary<Control, string> dictFormControls = new Dictionary<Control, string>();
foreach (Control c in Controls)
{
if (c is ComboBox)
{
dictFormControls.Add(c, ((ComboBox)c).SelectedValue.ToString());
}
if (c is TextBox)
{
dictFormControls.Add(c, ((TextBox)c).Text);
}
if (c is MaskedTextBox)
{
dictFormControls.Add(c, ((MaskedTextBox)c).Text);
}
}
if (discNumber <= Convert.ToInt32(numDiscs))
{
frmAddVideo frm = new frmAddVideo(numDiscs, discNumber, videoID, sequenceID, dictFormControls);
frm.Show();
this.Close();
}
I want the dictionary basically look something like this:
Key ------------ Value
"txtName" ----- "Test"
"txtYear" ------ "1980"
I am passing this back into the same form (frmAddVideo):
public frmAddVideo(string numDiscs, int discNumber, string videoID, string sequenceID, Dictionary<Control, string> dict)
{
this.numDiscs = numDiscs;
this.discNumber = discNumber;
this.videoID = videoID;
this.sequenceID = sequenceID;
InitializeComponent();
//This is where I want to parse out the Dictionary and populate the form values
foreach (KeyValuePair<Control, string> item in dict)
{
**Basically, I am looking for a way to take **
**item(Key)**
**and do something like item(Key).Value = item(Value);**
**so it would be the same as writing**
**txtName.Text= "1980";**
**cbxLocID.Value = 1;**
}
}
I am looking for a way to take key and turn it into the control name, then add ".Text" or ".Value" to it and then set the value to item(value) as I explained in the code above.
Is this possible? I tried researching this, but I have yet to put 2 and 2 together.
You may just store the set of controls you work with in your dictionary:
class ControlBoundValueDescription
{
private Control _control;
public ControlBoundValueDescription(Control control)
{
_control = control;
}
public string Value
{
get
{
if(_control is ...) return ...
...
}
set
{
if(_control is ...) ((Xxx)_control).Yyy = value;
...
}
}
}
...
Dictionary<string, ControlBoundValueDescription> dictControls =
new Dictionary<string, ControlBoundValueDescription>();
...
// defining mappings (you may also want to populate it automatically,
// by iterating over all the controls you have on your form)
dictControls["UserName"] = new ControlBoundValueDescription(tbUserName);
dictControls["Group"] = new ControlBoundValueDescription(cbxGroup);
...
// working with controls using previously defined mappings
dictControls["UserName"].Value = "guest"; // probably, text box
dictControls["Group"].Value = "Guest Users"; // probably, combo
But the whole idea seems to be bad design. You should probably clarify the problem you're trying to solve.
If I understand your question, you can use Find()
((TextBox)myForm.Controls.Find(Key, true)).Text = Value;
((CheckBox)myForm.Controls.Find(Key, true)).Checked = Boolean.Parse(Value);