Update Control on User Control from Main Form - c#

Background
I have a main form that has a tableLayoutPanel. Within that I have three panel, a header, footer and left side bar. In the remaining space I add and remove usercontrols this one in the example is called ctrlmanagepreset.
Within these usercontrols I have controls. Namely a Listsbox s, that i'm trying to add items too.
I am getting the items from an xml file that does contain items and reading them in to an object list. The name of each object is then added to the listbox.
All of the Controls are accessable as I've made them public. I think it might be due to the way i create and add them?
Question
Why aren't the Listboxes updating, showing the added items?
Code
Button click event that creates usercontrol
public void btnManage_Click(object sender, EventArgs e)
{
tableLayoutPanel.Controls.Add(new ctrlManagePresets () { Dock = DockStyle.Left }, 1, 1);
PopulateCreateJob();
}
Method that Populates Listbox
public void PopulateCreateJob()
{
ctrlManagePresets ctrlmanagepresets = new ctrlManagePresets();
//read in contents of xml file
if (File.Exists(JoblistXmlFilepath))
{
XmlSerializer deserializer = new XmlSerializer(typeof (List<Favourite>));
TextReader reader = new StreamReader(JoblistXmlFilepath);
//create list of old fave objects
var xmlList = (List<Favourite>) deserializer.Deserialize(reader);
reader.Close();
if (xmlList.Count > 0)
{
foreach (Favourite t in xmlList)
{
//add favourite objects to combobox
try
{
ctrlmanagepresets.lbCreateJob.Items.Add(t.Name);
}
catch
{
MessageBox.Show(#"There is an object with no name in the XML.", #"Message",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
}
ctrlmanagepresets.lbCreateJob.Refresh();
}
else
{
ctrlmanagepresets.lbCreateJob.Items.Add(#"Settings File Not Found");
ctrlmanagepresets.lbCreateJob.Enabled = false;
ctrlmanagepresets.lbCreateJob.BackColor = Color.DarkRed;
}
}

You are not adding the items to the instance of the control that you add to your tableLayoutPanel.
Just make your PopulateCreateJob return the instance that is built and intialized with the xml data
public void btnManage_Click(object sender, EventArgs e)
{
ctrlManagePresets ctrl = PopulateCreateJob();
ctrl.Dock = DockStyle.Left;
tableLayoutPanel.Controls.Add(ctrl, 1, 1);
}
public ctrlManagePresets PopulateCreateJob()
{
ctrlManagePresets ctrlmanagepresets = new ctrlManagePresets();
// current code that initialize the instance of your control
....
// return the control instance initialized to the caller
return ctrlmanagepresets;
}

Related

C# TabControl.SelectedIndex changes value unexpectedly

I have a method called OpenURL() and recordHistory() with the following definitions:
public string OpenURL(string url)
{
//get index of current tab
int tabIndex = BrowserWindow.TabControlE.SelectedIndex;
//create instance of History class
History H = new History();
//call recordHistory() method to record the url and tabIndex
H.recordHistory(url, tabIndex);
}
public void recordHistory(string url, int tabIndex)
{
//print the tabIndex
Console.WriteLine("Tab is: "+tabIndex);
}
The scenario is: I would like to record history for each tab.
However, I am facing some unexpected behavior from TabControl.SelectedIndex.
When the first tab is created, the output in recordHistory() is:
Tab is: -1
When I refresh the page (call OpenURL() on the same tab), this time the output in recordHistory() is:
Tab is: 0
It seems that the first time a tab is created the TabControl.SelectedIndex value is wrong. This goes away after refreshing the page. How do I correct this so that it displays the correct value?
EDIT: Adding the recordHistory() call.
In class BrowserWindow:
private void BrowserWindow_Load(object sender, EventArgs e)
{
TabControl1 = new TabControl();
TabControl1.SelectedIndexChanged += TabControl1_SelectedIndexChanged;
Tab Tab1 = new Tab(tab_counter, getHomePageURL());
TabControl1.Controls.Add(Tab1.createNewTab());
this.Controls.Add(TabControl1);
}
In class Tab:
class Tab
{
int tab_ID;
String tab_URL;
TabPage page;
public Tab(int tab_ID, String tab_URL)
{
this.tab_ID = tab_ID;
this.tab_URL = tab_URL;
}
public TabPage createNewTab()
{
//Create a new tab
page = new TabPage("New Tab");
page.Text = this.tab_URLE;
page.Controls.Add(R1);
R1.Text = OpenURL(this.tab_URLE);
return page;
}
}
The flow goes: BrowserWindow_Load() --> createNewTab() --> OpenURL() --> recordHistory()
The problem is with your BrowserWindow_Load event. Change the order of the last 2 statements and it should work. Like this:
private void BrowserWindow_Load(object sender, EventArgs e)
{
TabControl1 = new TabControl();
TabControl1.SelectedIndexChanged += TabControl1_SelectedIndexChanged;
Tab Tab1 = new Tab(tab_counter, getHomePageURL());
this.Controls.Add(TabControl1);
TabControl1.Controls.Add(Tab1.createNewTab());
}

ListBox doesn't show collection of objects in C#

EDITED! WORKING CODE
I have the following class:
class Medic
{
private readonly int codM;
private string numeM;
private string specialitate;
//i have a constructor and properties with get and set, correctly written
}
I added 3 textBoxes to the form to be filled, each one related to one of the class attributes.
After this i have a button, and if all 3 textbox fields are correctly completed, a new class object is created.
This object will be added to a List. And this list of objects I want to be displayed in a listBox, and be updated as I add new objects.
Also, I want to have 2 objects already in the List and displayed in the listBox as I run the program, created in the code I mean, not using the textBoxes, and the new entered objects to come after these. I barely know where to write the code to create these 2 objects, same as where is ok to create and populate the List of objects or to write the code to bind this list into the ListBox;
public partial class Form1 : Form
{
List<Medic> listaMedici = new List<Medic>();
Medic m1 = new Medic(0, "ion", "endocrinologie");
public Form1()
{
InitializeComponent();
listaMedici.Add(m1);
}
private void button1_AddObject_Click(object sender, EventArgs e)
{
if (textBox1_cod.Text == "")
errorProvider1.SetError(textBox1_cod, "Introduceti codul medicului!");
else if (textBox2_nume.Text == "")
errorProvider1.SetError(textBox2_nume, "Introduceti numele medicului");
else if (Regex.IsMatch(textBox2_nume.Text, #"^[ a-zA-Z]+$") == false)
errorProvider1.SetError(textBox2_nume, "Numele contine doar litere si spatii");
else if (textBox3_specialitate.Text == "")
errorProvider1.SetError(textBox3_specialitate, "Introduceti specialitatea medicului");
else
{
try
{
Medic medic = new Medic(Convert.ToInt32(textBox1_cod.Text), textBox2_nume.Text, textBox3_specialitate.Text);
foreach (Medic m in listaMedici)
{
if (textBox1_cod.Text == m.CodM.ToString())
{
throw new Exception("Codul contractului incalca proprietatea de unicitate. Introduceti un cod unic");
textBox1_cod.Clear();
}
}
listaMedici.Add(medic);
listBox1_medici.DataSource = new ObservableCollection<Medic>(listaMedici);
listBox1_medici.DisplayMember = nameof(Medic.NumeM);
listBox1_medici.ValueMember = nameof(Medic.CodM);
listBox1_medici.SelectedIndex = 0;
MessageBox.Show("ADDED!");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
errorProvider1.Clear();
textBox1_cod.Clear();
textBox2_nume.Clear();
textBox3_specialitate.Clear();
}
}
}
private void listBox1_medici_SelectedIndexChanged(object sender, EventArgs e)
{
}
The display member should be the name of the property to display, not a string property. Reflection is used to look for a property of the name of the display member. For example if your medic.NumeM value is "Hello" WPF will look for a property named "Hello", retrieve the value of the property and display it in the listbox.
In your case the code should be: listBox1_medici.DisplayMember = "NumeM";

Cannot find instance of dynamically added UserControl .Net

I have a UserControl which I am loading into a div which is inside an UpdatePanel. Here is my code for loading it:
controls.IDLControl IdlControl = LoadControl(#"~/controls/IDLControl.ascx") as controls.IDLControl;
IdlControl.ClientIDMode = ClientIDMode.Static;
IdlControl.ID = "IDLControl";
spGroup.Controls.Clear();
spGroup.Controls.Add(IdlControl);
And here is my code for trying to retrieve an instance of it:
controls.IDLControl IdlControl = RecursiveFindControl(this, "IDLControl") as controls.IDLControl;
private Control RecursiveFindControl(Control targetControl, string findControlId) {
if (targetControl.HasControls()) {
foreach (Control childControl in targetControl.Controls) {
if (childControl.ID == findControlId) {
return childControl;
}
RecursiveFindControl(childControl, findControlId);
}
}
return null;
}
But, all I get is null. I need help on figuring this out.
AFAIK, I need to re-add the control to the page on pre-init but it is one of the controls that can be added depending on which option is selected from a drop down list (which also is filled dynamically). I am stuck trying to figure out how to make this work.
You can try something like this to add your control back in the Page_Init based on the option selected in your DropDownList.
protected void Page_Init(Object sender, EventArgs e)
{
if (IsPostBack)
{
if (drpYourDropDown.Items.Count > 0 && drpYourDropDown.SelectedItem.Text == "yourOption")
{
AddIDLControl();
}
}
}
private void AddIDLControl()
{
controls.IDLControl IdlControl = LoadControl(#"~/controls/IDLControl.ascx") as controls.IDLControl;
IdlControl.ClientIDMode = ClientIDMode.Static;
IdlControl.ID = "IDLControl";
spGroup.Controls.Clear();
spGroup.Controls.Add(IdlControl);
}

Dynamically added objects and work with them

my code dynamically adding ListBoxes, which contains buttons. Buttons dynamically addind another buttons. Well... thats expectation. My code doesn't works.
Here is my code:
public Button createElements(string nameOfElement)
{
if (nameOfElement.Contains("Floor"))
{
// code creating Button
return floorButton;
}
else if (nameOfElement.Contains("Sound"))
{
// code creating Button
return soundButton;
}
else if (nameOfElement.Contains("Add"))
{
// code creating Button
return addButton;
}
return null;
}
private ListBox addNewListBox(ListBox targetElement, int ex)
{
// vytvori ListBox do hlavniho ListBoxu
ListBox elementListBox = new ListBox();
elementListBox.Name = "elementListBox" + indexY;
elementListBox.VerticalAlignment = VerticalAlignment.Top;
elementListBox.ItemsPanel = (ItemsPanelTemplate)XamlReader.Parse("<ItemsPanelTemplate xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"><StackPanel Orientation=\"Horizontal\"/></ItemsPanelTemplate>");
if (ex == 1)
{
targetElement.Items.Remove(addFloor);
targetElement.Items.Add(elementListBox);
elementListBox.Items.Add(createElements("Floor"));
elementListBox.Items.Add(createElements("Sound"));
elementListBox.Items.Add(createElements("Add"));
targetElement.Items.Add(addFloor);
indexY++;
indexX = 0;
}
return elementListBox;
}
Here is detail of final function.
private void putElements(ListBox targetElement, Button targetObject)
{
targetElement.Items.Add(targetObject);
// there's problem
MessageBox.Show("targetElement: ", targetElement.Name);
MessageBox.Show("targetObject", targetObject.Name);
}
Click event calling this function:
putElements(addNewListBox(mainListBox, 0), createElements("Sound"));
MessageBoxes prints names of objects in last function. Objects are right, but this line:
targetElement.Items.Add(targetObject);
there is problem - this line doing nothing..
Thanks for help!!
You're just adding the new ListBox to your mainListBox if the ex-value is 1, but in your case it's 0.
So your new ListBox (targetElement in putElements-method) will never be added to your mainListBox and hence not displayed. Thats why targetElement.Items.Add(targetObject); seems to not work.

Prevent multiple instances of a page in TabControl

I am making an application where i am opening wpf pages in tab control. But i am able to open same page again and again in tabcontrol. I want that if once page is opened it can't be opened again and it should get focused on tabcontrol if i try to open it again. i did following code but not working. I am using a custom closableTabItem Usercontrol.
private void Set_Fee_Click(object sender, RoutedEventArgs e)
{
// Adding page to frame and then adding that frame to tab item and then adding tab item to main tab.
FeeStructure feePage = new FeeStructure();
_closableTab = new ClosableTabItem();
_formFrame = new Frame();
_formFrame.Content = feePage;
_closableTab.Content = _formFrame;
_closableTab.Header = "Set Fee Structure";
if (!mainTab.Items.Contains(_closableTab))
{
mainTab.Items.Add(_closableTab);
_closableTab.Focus();
}
else
{
_closableTab.Focus();
}
}
private void Database_RecoveryBackup_Click(object sender, RoutedEventArgs e)
{
// Adding page to frame and then adding that frame to tab item and then adding tab item to main tab.
DbRecoveryBackup dbRecBack = new DbRecoveryBackup();
_closableTab = new ClosableTabItem();
_formFrame = new Frame();
_formFrame.Content = dbRecBack;
_closableTab.Content = _formFrame;
_closableTab.Header = "Data Base";
if (!mainTab.Items.Contains(_closableTab))
{
mainTab.Items.Add(_closableTab);
_closableTab.Focus();
}
else
{
_closableTab.Focus();
}
}
It'll never happen, what you want because you're creating a new instance of ClosableTabItem everytime, hence it is unique everytime, so .Items.Contains will never work in this case because it matches items using object.Equals.
Now, Since you said in question that you only want one instance of ClosableTabItem, then
using Linq, you can check if in the items there exist any item of type ClosableTabItem,
...
// Here we're checking the array 'Items',
// if it contains any item whose type is 'ClosableTabItem'
if (!mainTab.Items.Any(item => item is ClosableTabItem)))
...

Categories

Resources