I am currently using EasyTabs for C#, and it's working fine but I need to be able to at least change the title of the tab from my application, and I can't seem to find anything that will let me do that so far. I'm talking about changing the tab name not the entire form name just the tab names at the top of the screen.
so I need to be able to take a variable from Form1 and change the tab name, again not all the tabs, but specific tabs that get opened, depending on the page, the variable will be different and each tab needs to be named respectively, just as it would if you were going to different sites in different tabs in chrome.
I have looked at all possible stack overflow questions that already exist and none have really helped, so any help on this would be greatly appreciated, and at this point, I would be happy with even only have tab names and not being able to change the favicon, but both would be amazing.
AppContainer.cs
using System;
using EasyTabs;
public partial class AppContainer : TitleBarTabs
{
public AppContainer()
{
InitializeComponent();
AeroPeekEnabled = true;
TabRenderer = new ChromeTabRenderer(this);
Icon = Properties.Resources.icon;
Text = "Example";
}
public override TitleBarTab CreateTab()
{
return new TitleBarTab(this)
{
Content = new Form1
{
Text = "New Tab"
}
};
}
private void AppContainer_Load(object sender, EventArgs e)
{
}
}
Form1.cs
using EasyTabs;
using System.Windows.Forms;
public partial class Form1 : Form
{
protected TitleBarTabs ParentTabs
{
get
{
return (ParentForm as TitleBarTabs);
}
}
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
Program.cs
using System.Windows.Forms;
using EasyTabs;
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
AppContainer container = new AppContainer();
container.Tabs.Add(
new TitleBarTab(container)
{
Content = new Form1
{
Text = "New Tab"
}
}
);
container.SelectedTabIndex = 0;
TitleBarTabsApplicationContext applicationContext = new TitleBarTabsApplicationContext();
applicationContext.Start(container);
Application.Run(applicationContext);
}
}
I've seen the answer before on github a while back, you can change the tab name using ParentTabs.SelectedTab.Caption = e.Title;
I'm not entirely sure where "ParentTabs" was supposed to be located though, if you figure it out please update us
Edit; Sorry for the vague answer. In order to have the ParentTabs variable, you need this code:
protected TitleBarTabs ParentTabs
{
get
{
return (ParentForm as TitleBarTabs);
}
}
You will also need to invoke a new action and Redraw the tabs, using ParentTabs.RedrawTabs();
if you wish to show a favecon and have a title show then use the following
Favecon Code:
private void WebUI_AddressChanged(object sender, AddressChangedEventArgs e)
{
_ = this.Invoke(new MethodInvoker(() =>
{
URLSearch.Text = e.Address;
{
Uri url = new Uri("https://" + new Uri(WebUI.Address).Host + "/favicon.ico");
try
{
Icon img = new Icon(new System.IO.MemoryStream(new
WebClient().DownloadData(url)));
this.Icon = img;
}
catch (Exception)
{
this.Icon = Properties.Resources.tempIcon;
//change tempIcon to your desired icon, extension is .ico
}
}
}));
}
and this is for your Title Code:
private void WebUI_TitleChanged(object sender, TitleChangedEventArgs e)
{
this.Invoke((Action)delegate
{
FindForm().Text = e.Title;
});
}
and for all of this to work then you need to use the AddressChanged and TitleChanged Event in your main form like so
WebUI.AddressChanged += WebUI_AddressChanged;
WebUI.TitleChanged += WebUI_TitleChanged;
and that should wrap things up, i hope this helped you.
Related
I am making an application that loads a separate form, the user puts in information, and then when done, it will show up on the primary form the application loaded with first.
The issue is that I tried multiple solutions to get this to load in, but it will not load in after the information is put in. I have tried this.Controls.Add(Label); which is what I have seen the most, but it has not worked. Another way I tried was doing Label.Show();, but the same result, with nothing showing. The AddContacts(string Name) method below is how I add the contact
The AddContact_Click(object sender, EventArgs e) method is a button that, when pressed, opens another form that allows information to be inserted.
public partial class Phonebook : Form
{
public Phonebook()
{
InitializeComponent();
MaximumSize = new Size(633, 306);
}
private void AddContact_Click(object sender, EventArgs e)
{
MakeContact MC = new MakeContact();
MC.Show();
}
public void AddContacts(string Name)
{
Label name = new Label();
//Added Style and Location of Label...
name.Text = Name;
name.Location = new Point(98, 13);
name.Font = new Font("Microsoft Sans Serif", 13, FontStyle.Bold);
this.Controls.Add(name);
Refresh();
}
}
Below is the Method I used when the Finish button is pressed, for when the user is done with the information, and then the AddContacts() method is called
public partial class MakeContact : Form
{
public MakeContact()
{
InitializeComponent();
MaximumSize = new Size(394, 377);
}
private void FinishContact_Click(object sender, EventArgs e)
{
//FullName is the name of the TextField when asking for a name
string Name = FullName.Text;
Phonebook PB = new Phonebook();
PB.AddContacts(Name);
//Closes Separate Form and goes back to the
Close();
}
}
Expectation:
It should load the label into the form after the information is put in.
Actual:
It will not show what so ever.
EDIT: Added More to the Code and to the Question since I didn't do too good of asking the question, sorry about that :/
An example of what I described in the comments:
When you do this:
Phonebook PB = new Phonebook();
you create a new instance of the PhoneBook class (your form): this is not the same Form instance (the same object) that created the MakeContact Form and the one you're trying to update. It's a different object.
Whatever change you make to this new object, it will not be reflected in the original, existing, one.
How to solve:
Add a Constructor to the MakeContact Form that a accepts an argument of type PhoneBook and a private object of type Phonebook:
private PhoneBook pBook = null;
public MakeContact() : this(null) { }
public MakeContact(PhoneBook phoneBook)
{
InitializeComponent();
this.pBook = phoneBook;
}
Assign the argument passed in the constructor to the private field of the same type. This Field will then used to call Public methods of the PhoneBook class (a Form is a class, similar in behaviour to other class).
It's not the only possible method. You can see other examples here.
Full sample code:
public partial class Phonebook : Form
{
private void AddContact_Click(object sender, EventArgs e)
{
MakeContact MC = new MakeContact(this);
MC.Show();
}
public void AddContacts(string Name)
{
Label name = new Label();
// (...)
this.Controls.Add(name);
}
}
public partial class MakeContact : Form
{
private PhoneBook pBook = null;
public MakeContact() : this(null) { }
public MakeContact(PhoneBook phoneBook)
{
InitializeComponent();
this.pBook = phoneBook;
}
private void FinishContact_Click(object sender, EventArgs e)
{
string Name = FullName.Text;
this.pBook?.AddContacts(Name);
this.Close();
}
}
I am trying to create a C# Application with Chrome-Style Tabs using EasyTabs in WinForms, but I am getting the following error code:
The designer must create an instance of type 'EasyTabs.TitleBarTabs' but it cannot because the type is declared as abstract.
I have followed the Youtube-tutorial beneath as a guideline.
https://www.youtube.com/watch?v=WVFjegJK8EY
Code:
using System;
using EasyTabs;
namespace WindowsFormsApp1
{
public partial class AppContainer : TitleBarTabs
{
public AppContainer()
{
InitializeComponent();
AeroPeekEnabled = true;
TabRenderer = new ChromeTabRenderer(this);
}
public override TitleBarTab CreateTab()
{
return new TitleBarTab(this)
{
Content = Form1
{
Text = "New Tab"
}
};
}
private void AppContainer_Load(object sender, EventArgs e)
{
}
}
}
It is normal to see this error when you try to view AppContainer.cs directly.
The designer must create an instance of type 'EasyTabs.TitleBarTabs' but it cannot because the type is declared as abstract.
Let that not deter you from achieving what you wanted to achieve. Ignore the error and simply right click on AppContainer.cs and select View Code
using EasyTabs;
namespace WindowsFormsApp1
{
public partial class AppContainer : TitleBarTabs
{
public AppTabs()
{
InitializeComponent();
AeroPeekEnabled = true;
TabRenderer = new ChromeTabRenderer(this);
Icon = mBible.Properties.Resources.appico;
}
public override TitleBarTab CreateTab()
{
return new TitleBarTab(this)
{
Content = new Form1
{
Text = "New Tab"
}
};
}
}
}
That should be enough to generate new tabs for you.
Now to create tabs easily lets assume you have a form 'MainForm' and the tab you want to be generating is 'Form1' here is what we do
using System;
using System.Windows.Forms;
using EasyTabs;
namespace WindowsFormsApp1
{
public partial class MainForm : Form
{
public static AppContainer tabbedApp = new AppContainer();
public MainForm()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
tabbedApp.Tabs.Add(new TitleBarTab(tabbedApp)
{
Content = new Form1
{
Text = "New Tab"
}
});
tabbedApp.SelectedTabIndex = 0;
TitleBarTabsApplicationContext applicationContext = new TitleBarTabsApplicationContext();
applicationContext.Start(tabbedApp);
this.Hide();
}
}
}
You can always add to your tabs a new tab easily by calling this code on another form
AppContainer.tabbedApp.Tabs.Add(new TitleBarTab(AppContainer.tabbedApp)
{
Content = new Form2 { Text = "Another Tab" }
});
AppContainer.tabbedApp.SelectedTabIndex = 0;
I hope that helps and anyone looking for help on similar issues.
I try to developp an app for users to create a lot of computer's configuration, with OS / Language / etc ...
When he validate a configuration, I would like the choices to be stored in a custom attribute button
private void VALIDATE_Click(object sender, EventArgs e)
{
string Computer = Text_Computer.Text;
if (myList.Any(str => str.Contains(Computer)))
{
MessageBox.Show(Computer+"Already Exist");
}
else
{
Button button = new Button();
button.Size = new System.Drawing.Size(195, 30);
button.Tag = Computer;
button.Name = Computer;
button.Text = Computer;
button.CustomOS = comboBox_OS.SelectedItem;
button.CustomLanguage = comboBox_Language.SelectedItem;
flowLayoutPanel3.Controls.Add(button);
myList.Add(Computer);
MessageBox.Show(Computer + "added");
}
In my GUI, if Users want to edit a configuration, he click on the new button representing the configuration and all choices are back, like :
comboBox_OS.SelectedItem = button.CustomOS;
comboBox_Language.SelectedItem = button.CustomLanguage;
Is that possible to create my custom attribute like button.CustomOS and button.CustomLanguage ?
Regards
It is possible and quite easy. You just derive a new class from the original Button and declare two new Properties. I included the code into a simple example.
using System;
using System.Windows.Forms;
namespace StackOverflow
{
public partial class FormMain : Form
{
public FormMain()
{
InitializeComponent();
}
private void cbOS_SelectedIndexChanged(object sender, EventArgs e)
{
//Save selection.
ComboBox cb = (ComboBox)(sender);
btn1.CustomOS = cb.SelectedItem.ToString();
}
private void btnSelect_Click(object sender, EventArgs e)
{
//Restore selection on click.
MyButton btn = (MyButton)(sender);
cbOS.SelectedItem = btn.CustomOS;
}
//Declare a new class deriving from the original Button.
public class MyButton : Button
{
public String CustomOS { get; set; }
public String CustomLanguage { get; set; }
}
}
}
In the windows forms project i created a new class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FTP_ProgressBar
{
class FtpConfig
{
public static string txtHost;
public static string txtUsername;
public static string txtPassword;
public static string txtDir;
public static string txtUploadFile;
public static string txtPort;
public static System.Windows.Forms.CheckBox chkPassive;
public static FtpSettings f;
}
}
And in form1 i have a click button where i'm calling a method with the settings:
private void btnUpload_Click(object sender, EventArgs e)
{
FtpSettings();
}
Then:
private void FtpSettings()
{
if (this.ftpProgress1.IsBusy)
{
this.ftpProgress1.CancelAsync();
this.btnUpload.Text = "Upload";
}
else
{
FtpConfig.txtHost = this.txtHost.Text;
FtpConfig.txtUsername = this.txtUsername.Text;
FtpConfig.txtPassword = this.txtPassword.Text;
FtpConfig.txtDir = this.txtDir.Text;
FtpConfig.txtUploadFile = this.txtUploadFile.Text;
FtpConfig.txtPort = this.txtPort.Text;
FtpConfig.chkPassive = this.chkPassive;
this.toolStripProgressBar1.Visible = true;
this.ftpProgress1.RunWorkerAsync(FtpConfig.f);
this.btnUpload.Text = "Cancel";
}
}
The problem is that i have in my form1 designer a control i dragged over after adding dll file to the toolbox the control have like windows explorer with treeView1 and listView1:
The explorer windows is the left one with the C node tree expanded.
The problem is i need somehow to call/use the FtpSettings() method in form1 with the dll library class in this event:
void menuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
if (e.ClickedItem.Text == "Upload")
{
List<String> selected = new List<String>();
string dir = treeView1.SelectedNode.FullPath;
dir = dir + "\\";
foreach (ListViewItem lvi in listView1.SelectedItems)
{
string g = Path.Combine(dir, lvi.Text);
selected.Add(g);
}
AllFiles = selected.ToArray();
FilesFromExplorerOrManual = false;
Bgw.RunWorkerAsync();
}
}
So after added the control dll file to my form1 toolbox dragged it to the form1 designer i need to call the FtpSettings method each time i click on Upload:
if (e.ClickedItem.Text == "Upload")
After this line: FtpSettings();
But first i don't have access to the event after dragging it to the form1 designer.
Second maybe i will need to call the FtpSettings() in other events in this dll.
I tried after dragging it in form1 designer then i have a variable: explorerTree1 so i tried to do in form1 constructor:
explorerTree1.MouseUp += explorerTree1_MouseUp;
Then:
void explorerTree1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
FtpSettings();
}
}
I used a breakpoint but it never stop/get to this event. And it also not the same event in the dll file that i need to get to.
You should be watching Drag and Drop events, instead. Please review the docs from Microsoft as the subject is quite extensive.
I created a custom form (FormBorderStyle = FormBorderStyle.None).
I draw my own caption bar at the top with my own custom caption buttons (Close, Maximize ...).
Now my only problem is adding normal user controls to that form. If I give these controls a location, the locations are relative to the form's top (including the caption bar).
I override the default ClientSize & ClientRectangle using the 'new' keyword, which allows me to adjust it (thus removing the caption bar out of it).
This does not seem to work and I haven't been able to figure out how to do this properly without 'hacking' the ControlAdded event (which is still buggy).
protected override void OnControlAdded(ControlEventArgs e)
{
base.OnControlAdded(e);
if (e.Control.GetType() != typeof(VlufiCaptionButton /* Caption buttons: close, minimize & maximize, should not be included */))
{
e.Control.Location = new Point(e.Control.Location.X + ClientRectangle.X, e.Control.Location.Y + ClientRectangle.Y);
e.Control.LocationChanged += Control_LocationChanged;
}
}
private void Control_LocationChanged(object sender, EventArgs e)
{
if (!childControlLocationChangedHandled)
{
System.Diagnostics.Debug.WriteLine("changing");
Control cControl = (Control)sender;
childControlLocationChangedHandled = true;
cControl.Location = new Point(cControl.Location.X + ClientRectangle.X, cControl.Location.Y + ClientRectangle.Y);
}
else
childControlLocationChangedHandled = false;
}
This is the code I currently use, but it's superbuggy & I'm still having other problems with my customly drawn border.
Does anybody know how I should correctly handle this ?
I found a decent solution: I added a ContainerControl to the form & I position & size this according to the form, then whenever adding a control to the form, it should be added to the ContainerControl. Still not a proper solution, but it's the best one so far.
I'd still appreciate if someone came up with another solution.
read comments for detail:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace WindowsApplication1
{
public partial class Form1 : Form
{
int dy = 0;
public Form1()
{
InitializeComponent();
//i add a panel to top form
//( for simulating your caption bar) and get its height
dy = panel1.Height; //for yours its your caption bar height
}
private void button1_Click(object sender, EventArgs e)
{
//adding button control between form top and panel end area
//( simulate in your caption bar )
Button btn = new Button();
btn.Location = new Point(panel1.Location.X+40,panel1.Location.Y+10);
btn.Text = "Salam";
this.Controls.Add(btn);
}
//in control added event i add dy ( height of ignored area) to control Location
private void Form1_ControlAdded(object sender, ControlEventArgs e)
{
e.Control.Location = new Point(e.Control.Location.X, e.Control.Location.Y + dy);
}
private void button2_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
Ok after all, I have finally found a working and pretty nice solution.
What I did is override the Controls property of my custom Form, using my own custom ControlCollection.
So this is what I got in my custom form:
public Control.ControlCollection RealControls
{
get
{
return base.Controls;
}
}
public new CustomControlCollection Controls { get; private set; }
public ContainerControl ControlContainer { get; set; }
And this is the custom ControlCollection:
public class CustomControlCollection
{
public VlufiForm Owner { get; private set; }
public CustomControlCollection (VlufiForm pOwner)
{
Owner = pOwner;
}
public void Add(Control c)
{
Add(c, false);
}
public int Count
{
get
{
return Owner.ControlContainer.Controls.Count;
}
}
public Control this[int index]
{
get
{
return Owner.ControlContainer.Controls[index];
}
}
public void Add(Control c, bool isUsable)
{
if (isUsable)
Owner.RealControls.Add(c);
else
Owner.ControlContainer.Controls.Add(c);
}
public void SetChildIndex(Control c, int nIndex)
{
Owner.ControlContainer.Controls.SetChildIndex(c, nIndex);
}
}
This is just an example custom control collection, you could add more methods in it (thus kind of inheriting ControlCollection more).
I haven't found any bugs in this system yet, it works perfectly at the moment.
EDIT: found a bug, if you dock a control in Visual Studio's Designer Mode, it will dock in the whole form, this doesn't appear when running though.