I have a form with a button and a tabcontrol. If I click on the button, it adds a new tab with a listbox inside the richtextbox of the tabcontrol, but once I move through the tabs, the listbox is only visibile/available on the newest tab and not in the previous tabs. Anyway ideas on how to fix this please? Below is my code:
private void button1_Click(object sender, EventArgs e)
{
if (tabControl1.Visible == false)
{
tabControl1.Visible = true;
listBox1.Visible = true;
}
TabPage tp = new TabPage();
RichTextBox rtb = new RichTextBox();
int tc = (tabControl1.TabCount + 1);
rtb.Controls.Add(listBox1);
tp.Text = "New " + tc.ToString();
tabControl1.TabPages.Add(tp);
rtb.Dock = DockStyle.Fill;
tp.Controls.Add(rtb);
return;
}
Your code is adding the same listbox to the new richtextbox you are creating; when the last added richtextbox is hidden (by moving to a different tab), the listbox is also hidden. You have two options:
Create a listbox for each richtextbox
Handle the selection change for the tab control and reattach the listbox to the currently visible richtextbox.
Related
I have a ContextFlyout in my form and I want the listbox to select the index where the mouse is upon right-click
Originally I thought I could take advantage of the RightTapped event so I created an event handler, but while filling out the method, I didn't see any way to translate the position of the mouse to an item in the listbox.
RightTapped event
private void SideMenu_RightClick(object sender, RightTappedRoutedEventArgs e) {
ListBox menu = (ListBox)sender;
SideMenu.SelectedIndex = menu.IndexFromPoint(e.);
menu.
}
I've looked through all the methods and properties but I can't seem to find what I need. I found a lot of solutions for WPF, but this is UWP and those methods do not exist on these UWP objects
An easier approach would be to attach the event handler to the ListBoxItem or the root element in the ItemTemplate. You'll find an example of how you could do this here.
I figured out how to do it. Firstly, both my MenuFlyout and items for the listbox are generated programmatically.
Creating MenuFlyout
//this is a property in the class
internal MenuFlyout rightclick = new MenuFlyout();
//In Page's Constructor
this.InitializeComponent();
MenuFlyoutItem mfi = new MenuFlyoutItem();
mfi.Text = "Copy";
rightclick.Items.Add(mfi);
mfi = new MenuFlyoutItem();
mfi.Text = "Delete";
rightclick.Items.Add(mfi);
rightclick.Opened += rightclick_opened; //run method when flyout is opened
Method for the Opened event
private void rightclick_opened(object sender, object e) {
MenuFlyout mf = (MenuFlyout)sender;
SideMenu.SelectedItem = mf.Target; //makes the magic happen
}
Instantiating ListBoxItems
private void NewLocation(object sender, RoutedEventArgs e) {
Location newLocation = new Location(); //custom class
ListBoxItem nl = new ListBoxItem(); //creates empty ListBoxItem
nl.Content = newLocation.objectName; //give listboxitem default name from the class constructor
nl.ContextFlyout = rightclick; //set contextflyout for item
SideMenu.Items.Add(nl); //add new item to listbox
locations.Add(newLocation); //add new object to "linked" list
SideMenu.SelectedIndex = locations.Count - 1; //set current selected to new item
}
I am generating wpf form dynamically. All the controls are generated dynamically as follows
A sample code snippet
String tbname = name;
TextBlock txtBlock1 = new TextBlock();
txtBlock1.Text = tbname;
Grid.SetRow(txtBlock1, count);
Grid.SetColumn(txtBlock1, icount);
SampleGrid.Children.Add(txtBlock1);
TextBox txtBox = new TextBox();
txtBox.Text = ptiAttribute.description;
txtBox.Name = tbname.Replace(" ", "");
DynamicGrid.RegisterName(txtBox.Name, txtBox);
Grid.SetRow(txtBox, count);
Grid.SetColumn(txtBox, icount+1);
SampleGrid.Children.Add(txtBox);
Attaching a button click event as follows
var Button = CreateButton("Save", 15, 3);
Button.Click += new RoutedEventHandler(button_Click);
SampleGrid.Children.Add(Button);
I would like to get all the control values (For example: The above text box has value Book), I have to get it after button click. I am not only having text box. I have combo box, date picker too. I don't know which name is registered (RegisterName). Every thing dynamic.
private static void button_Click(object sender, RoutedEventArgs e)
{
# How to get dynamic values here (text bx value, date picker value, combo box value)
}
Simply, how to get values from dynamically generated controls. I have gone through a lot of Visual tree links but I don't know how it works on button click.
Any simple code snippet will help me to move ahead. Thanks
I'm not used to WPF but try this approach(inspired by this):
private static void button_Click(object sender, RoutedEventArgs e)
{
Button btn = (Button)sender;
int row = Grid.GetRow(btn);
TextBox txtBox = SampleGrid.Children
.OfType<TextBox>()
.First(txt => txt.Name == name && Grid.GetRow(txt) == row);
// ...
}
I am using tab control, and there is one label that showing customer's name that I want to display in all three 3 tabs. However, if I put it on tab 1, then it won't show on tab 2 and 3, even thought that the name of the label is unique. Is there a way to do that ? or do I have to create 3 different labels ? thanks a lot.
This might work for you. When changing tabs. Add the label to the TabPage's Controls collection. When adding the label to the new TabPage it gets removed from the previous TabPage so you have to re-add it every time you change tabs.
public partial class Form1 : Form
{
Label label = new Label() { Text = "Hello World" };
public Form1()
{
InitializeComponent();
tabControl1.TabPages[0].Controls.Add(label);
}
private void tabControl1_Selected(object sender, TabControlEventArgs e)
{
e.TabPage.Controls.Add(label);
e.TabPage.Controls.SetChildIndex(label, 0);
}
}
Position label1 in your desired location in the TabPage at design-time, then switch it to the Form in the Load() event using code like this:
private void Form1_Load(object sender, EventArgs e)
{
Point pt = label1.PointToScreen(new Point(0, 0));
label1.Parent = this;
label1.Location = this.PointToClient(pt);
label1.BringToFront();
}
You should put on form 2 panels.
1st panel should have Docking = Top and with height equal to height of your label. Put your label there (on 1st panel).
2nd panel should have Docking = Fill, put your tab control on 2nd panel.
I'm creating a simple notepad type of application with the tab functionality. I'm creating the TabControl, its TabPages and RichTextBoxes at run-time. I have them instantiated at class scope. And there is a MenuStrip item called New, by clicking that you can add more tab pages.
TabControl tbcEditor = new TabControl();
TabPage tbPage = new TabPage();
RichTextBox rtb = new RichTextBox();
private void frmTextEditor_Load(object sender, EventArgs e)
{
Controls.Add(tbcEditor);
tbcEditor.Dock = DockStyle.Fill;
tbcEditor.TabPages.Add(tbPage);
tbPage.Controls.Add(rtb);
rtb.Dock = DockStyle.Fill;
}
private void newToolStripMenuItem_Click(object sender, EventArgs e)
{
//TabPage tbPage = new TabPage();
//RichTextBox rtb = new RichTextBox();
tbPage.Controls.Add(rtb);
rtb.Dock = DockStyle.Fill;
tbcEditor.TabPages.Add(tbPage);
}
The problem I'm facing is a bit difficult to explain. I'll try my best. When the form loads, everything works as expected. The TabControl creates with a TabPage with a RichTextBox added. However if I click that New button to add another page, it goes bonkers. A new TabPage gets created but without a RichTextBox added. No errors are thrown either. If I un-comment out those 2 lines(under MenuItem click event), which creates 2 instances of TabPage and RichTextBox, everything works as I want.
Now my first question is why do I have to make new instances of only those 2 types(TabPage, RichTextBox) again but not TabControl? As you can see in the last line, I can use tbcEditor once again. But not tbPage and rtb.
Sure I can go on declaring them again at local scope but another issue arises then. If I want to say, add copy, paste functionality, I should do something like this,right?
Clipboard.SetDataObject(rtb.SelectedText);
But I can't access rtb since it is declared as local.
I'm very baffled by this so any suggestions, ideas on how to overcome these 2 issues would be greatly appreciated.
Thank you.
If I un-comment out those 2 lines(under MenuItem click event), which creates 2 instances of TabPage and RichTextBox, everything works as I want.
When you uncomment those lines, you are adding the same instance of the rich textbox and tab page to the container panel again which is meaningless. Instead add new controls foreach tabpage. (I hope thats the requirement)
Now my first question is why do I have to make new instances of only those 2 types(TabPage, RichTextBox) again but not TabControl?
TabControl is the parent control which has TabPages as child controls. You can have multiple tabs under one TabControl. So you need not create TabControls other than the tbcEditor you have already added. We do not add container controls more than once (unless its the requirement). Do we need more forms? No, just one form which can hold all the child controls right. Similarly just one TabControl which can hold a collection of TabPages. You would need more TabControls only if you want sub-tabs foreach new tab which I guess is not the requirement..
But I can't access rtb since it is declared as local.
This is no big deal. You can do in two ways:
1) Search for your appropriate control by looping. The SelectedTab property gives what you want.
private void someEvent(object sender, EventArgs e)
{
foreach (Control c in tbcEditor.SelectedTab.Controls)
{
if (c is RichTextBox)
{
Clipboard.SetDataObject(((RichTextBox)c).SelectedText);
break; //assuming u have just one main rtb there
}
}
}
2) Tag each rtb to the tabPage when you create it, and then you can get the tag element of the selected tab page to get the rich text box. I would go for this approach.
Edit: (In general pls make the following changes too to your code):
TabControl tbcEditor = new TabControl();
private void frmTextEditor_Load(object sender, EventArgs e)
{
Controls.Add(tbcEditor);
tbcEditor.Dock = DockStyle.Fill;
AddMyControlsOnNewTab();
}
private void AddMyControlsOnNewTab()
{
TabPage tbPage = new TabPage();
RichTextBox rtb = new RichTextBox();
tbPage.Tag = rtb; //just one extra bit of line.
tbcEditor.TabPages.Add(tbPage);
tbPage.Controls.Add(rtb);
rtb.Dock = DockStyle.Fill;
}
private void newToolStripMenuItem_Click(object sender, EventArgs e)
{
AddMyControlsOnNewTab();
}
Now, you can call it like this:
private void someEvent(object sender, EventArgs e)
{
RichTextBox rtb= (RichTextBox)tbcEditor.SelectedTab.Tag;
Clipboard.SetDataObject(rtb.SelectedText);
//or even better in just a line,
//Clipboard.SetDataObject(((RichTextBox)tbcEditor.SelectedTab.Tag).SelectedText);
}
What you have to consider here is which is the control that you first get and which is the one you do not get. You would get TabPage anyways but not the RichTextBox. So you have to tag RichTextBox to TabPage. You have to cast it since Tag is of type object, so you have to specify which kind of object it is. Finally, this method has the advantage that you need not loop through a list, so its more performant. And that you can have more RichTextBoxes in the TabPage (provided you want to copy text from only one set of RichTextBoxes, one from each TabPage)..
The commented lines are doing just what they are suppposed to do. The code does not associate the Richtextbox with the Tabpage .
TabPage tbPage = new TabPage(); // Creates a new tabpage
RichTextBox rtb = new RichTextBox(); // Creates a new RichtextBox control.
TabControl is a container , so one instance is just fine.
Also see this - http://sujay-ghosh.blogspot.in/2009/03/addingremoving-dynamically-created.html, nothing with do with tabcontrols, but how to create controls on the fly.
Hope this helps .
The code
tbPage.Controls.Add(rtb);
rtb.Dock = DockStyle.Fill;
tbcEditor.TabPages.Add(tbPage);
Takes your exisitng textbox, adds it to the exisitng tab page, then adds that existing tab page to the editor. Since this has already been done, nothing happens.
When you add those two lines, you create new instances of the text box and a new tab page, which is exactly what you want. Your latter problem comes, because the newly declared variable rtb hides the one declared in the class -- in a different method you can only access the onde declared in the class (barring getting the control out of the tab)
To get around not being able to access the proper text box, you can maintain them in a list(*) (or some other collection) and refer to the one associated with the currently active tab. For this, you will have to create an event listener to see which tab is activated currectly.
(*) as opposed to having only one
OK you need to create fresh instances of the RichTextBox rathere than trying to add the same instance to each tab.
TabControl tbcEditor = new TabControl();
//Get rid off this line --- TabPage tbPage = new TabPage();
//Get rid off this line --- RichTextBox rtb = new RichTextBox();
List<TabPage> _tabs = new List<TabPage>();
List<RichTextBox> _tbx = new List<RichTextBox>();
private void frmTextEditor_Load(object sender, EventArgs e)
{
Controls.Add(tbcEditor);
tbcEditor.Dock = DockStyle.Fill;
AddNewTab();
}
private void newToolStripMenuItem_Click(object sender, EventArgs e)
{
AddNewTab();
}
private void AddNewTab()
{
//TabPage
var tbPage = new TabPage();
_tabs.Add(tbPage);
//RichTextBox
var rtb = new RichTextBox();
_tbx.Add(rtb);
tbPage.Controls.Add(rtb);
rtb.Dock = DockStyle.Fill;
tbcEditor.TabPages.Add(tbPage);
}
This simply add both the tab and the rtb to a collection which can be accessed by index (can also use Dictionary for named access etc). There are other ways of course, including just nameing the components and looping through for them when required etc.
I created a page where I give admin's a way to change photos info (e.g. Title, Description, etc) All the controls on the page are added dynamically because I have more than one gallery of photos.
panel --> parent.
button .
title text box.
description text box.
In every panel, I have button that when clicked, sends the changed information to the server where the photo info is stored (Flickr). The click event for this button is added dynamically, and I want to know if is possible to get the parent of the Button I just clicked on.
Here is the code where I add all my controls:
//global veriables (this is only part of the code)
Panel panel;
Button button;
for (int i = 0; i < photo.Length; i++) {
photo[i] = new FlickerImages(photoSet.MediumURLS[i], photoSet.ThumbnailURLS[i], photoSet.Titles[i], photoSet.Descreption[i]);
panel = new Panel();
panel.ID = "panel" + i;
button = new Button();
button.ID = "sendDataButton" + i;
button.Text = "send data";
button.Click += button_Click; //adding the event
label = new Label();
label.ID = "editLabel" + i;
panel.Controls.Add(label);
panel.Controls.Add(photo[i].CurrentImage(i)); //Image control
panel.Controls.Add(photo[i].EditTitleTextBox(i)); //TextBox control
panel.Controls.Add(photo[i].EditCommentTextBox(i)); //TextBox control
panel.Controls.Add(button);
Form.Controls.Add(panel);
}
Here is the click event I add to all the buttons:
void button_Click(object obj, EventArgs e) {
Response.Write(button.Parent.ID); // i get panel10 every time this get fired.
}
I know this is possible with jQuery but is it possible to get the button ID in ASP.NET?
Sorry for my English and thanks for the help.
Not sure, but are you looking for the ClientID property? (button.Parent.ClientID)
Edit:
You should reference the sending button in the event handler:
void button_Click(object obj, EventArgs e)
{
Response.Write(((Button)obj).Parent.ID);
}