Application with Chrome-Style Tabs using EasyTabs in WinForms - c#

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.

Related

Cannot declare a UserControl in file code

I have had a problem. I create an UserControl and I save it, it appears in ToolBox. I can drop it from ToolBox normally. However, I can not declare it as a variable in the file code. Can you help me, please? And it is file code of UserControl
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Music_Player_Project_IT008N13.Controls;
namespace Music_Player_Project_IT008N13.Music_design_User_Control
{
public partial class LocationPanel : UserControl
{
public LocationPanel()
{
InitializeComponent();
}
public delegate void DoEvent(string maSo, string tenSV, string khoa, string diemTB);
public event DoEvent RefeshDgv;
private void btnDelete_Click(object sender, EventArgs e)
{
}
}
}
When you "drop it from the ToolBox normally", the Designer generates a member declaration for a new user control and also adds it to the forms Control collection. As I understand it, your question states that you would like to declare your user control variable in code. If this is the goal, we have to do the same thing that the Designer would do and add it to the Controls collection of the container you want to put it in.
Example
Add a FlowLayoutPanel using code, then add 3 CustomUserControls to it also in code.
public partial class MainForm : Form
{
public MainForm() => InitializeComponent();
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
// Declare a flow layout panel in code.
// Add it to the main form control collection
var flowLayoutPanel = new FlowLayoutPanel
{
Name = "flowLayoutPanel",
Dock = DockStyle.Fill,
};
this.Controls.Add(flowLayoutPanel);
for (char c = 'A'; c < 'D'; c++)
{
var userControl = new CustomUserControl
{
Name = $"userControl{c}", // No space, start with lowercase
Text = $"UserControl {c}", // Visible name
Margin = new Padding(10, 2, 10, 2),
Width = flowLayoutPanel.Width - 20,
};
flowLayoutPanel.Controls.Add(userControl);
}
// T E S T
CustomUserControl? loopback = GetUserControl("userControlA");
Debug.Assert(loopback != null, "Expecting to retrieve user control by name");
}
Then, to use the control, retrieve it from the Controls collection by name.
CustomUserControl? GetUserControl(string name)
{
var layoutPanel = Controls["flowLayoutPanel"] as FlowLayoutPanel;
return layoutPanel.Controls[name] as CustomUserControl;
}
}
Where:
public partial class CustomUserControl : UserControl
{
public CustomUserControl() => InitializeComponent();
public new string Text
{
get => label1.Text;
set => label1.Text = value;
}
}

How to change tab name and favicon in EasyTabs?

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.

Textbox readonly property not working in TextBox made by me

I have a textbox (TextBoxMoeda) made by me, but, even when the textbox property readonly is set true. nothing happens. Anyone knows how to implement the code to resolve this problem?. Please help me?
public class TextBoxMoeda : TextBox
{
private double dp;
private string fmt = string.Empty;
private int _CasasDecimais = 0;
[Category("TextBoxMoeda")]
public virtual bool SomenteLeitura
{
get => base.ReadOnly;
set
{
base.ReadOnly = value;
Invalidate();
}
}
//Code Continues .......
}
WPF
You want the IsReadOnly property, not the ReadOnly property.
For example:
Create a new WPF App (.NET Framework) project called DeleteMe
In MainWindow.xaml, delete the Grid
In MainWindow.xaml.cs, use this code:
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace DeleteMe
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var tm = new TextBoxMoeda();
this.AddChild(tm);
tm.SomenteLeitura = true;
}
public class TextBoxMoeda : TextBox
{
[Category("TextBoxMoeda")]
public virtual bool SomenteLeitura
{
get => base.IsReadOnly;
set
{
base.IsReadOnly = value;
}
}
}
}
}
The textbox will be readonly (i.e. I can't type anything into the textbox).
WinForms
The code already appears to work in WinForms. These steps will produce a working project:
Create a new Windows Forms App project called DeleteMeAgain
Overwrite all of the Form1.cs code with this:
using System.ComponentModel;
using System.Windows.Forms;
namespace DeleteMeAgain
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var tm = new TextBoxMoeda();
this.Controls.Add(tm);
tm.SomenteLeitura = true;
}
public class TextBoxMoeda : TextBox
{
[Category("TextBoxMoeda")]
public virtual bool SomenteLeitura
{
get => base.ReadOnly;
set
{
base.ReadOnly = value;
Invalidate();
}
}
}
}
}
The textbox will be readonly (i.e. I can't type anything into the textbox).
Windows Form: User Control
Do this:
Create a new Windows Forms App called DeleteMe3
Set Target Framework to .NET Core 3.1 (Long-term support)
In your project, create a new UserControl with the filename TextBoxStack.cs
Overwrite all of the code for that user control with this:
using System.ComponentModel;
using System.Windows.Forms;
namespace DeleteMe3
{
public partial class TextBoxStack : TextBox
{
[Category("TextBoxStack")]
public virtual bool SomenteLeitura
{
get => base.ReadOnly;
set
{
base.ReadOnly = value;
Invalidate();
}
}
}
}
An error will appear. Go to the source of the error and delete that line.
Build the solution
Add your new user control to Form1
Select the new user control on the form
Change the SomenteLeitura property to True
Run the project. The textbox should be grey and readonly.

Generate custom C# code in Form.cs while dropping user control in Form1.cs at design time

I have a user control that I can drag and drop in the Form1.cs[Design] mode. The designer will auto-generate code for this user control in the Form1.Designer.cs
What I would like to get aswell is: at the moment I am adding the user control to the form by dragging I wont to have code generated in my Form.cs that is pointing to the properties and controls on that user control.
Example of user control:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public string TextInTextBox
{
get { return textBox1.Text; }
set { textBox1.Text = value; }
}
}
So now when I drag it on the form in the Form1.cs[Design]. I won't part of code like this to be generated in my Form1.cs:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
AddText();
}
// this code below to be auto-generated
private void AddText()
{
userControl11.TextInTextBox = "";
}
}
I think I should be looking for something like inheritance or interface but I would like this to happen for each instance of that user control.
If someone could point me direction what to look for it would be great. Thanks.
Usually you don't need to generate code manually when you want to assign a property when dropping a control from toolbox, for example you can easily do this:
public MyUserControl()
{
InitializeComponent();
MyTextProperty = "Something";
}
And it will be serialized automatically.
But there are more options for more advanced requirements.if you know the options that you have, you may choose based on your requirement. Here is some options:
Assign some value in constructor or to the property
Assign value to properties using ToolboxItem, it will overwrite the value which you assign in constructor.
Generate some code for Load event of form and initialize property there. It's useful for complex code generations, for example when you drop a data source it will generate some code to load data and add to load event of form.
Assuming you have assigned Something to MyTextProperty in constructor, then when you drop the control in form, here is what will be generated in designer.cs:
this.myUserControl1.MyTextProperty = "Something";
If you use the ToolboxItem solution to assign Something else to the property, the result in designer.cs file will be:
this.myUserControl1.MyTextProperty = "Something else";
And if you decide to use third option and generate event handler code, the result in designer.cs file will be:
this.Load += new System.EventHandler(this.Form1_Load);
and the result in cs file will be:
private void Form1_Load(object sender, EventArgs e)
{
myUserControl1.MyTextProperty = "Even something else!";
}
Example
Here is a full code of MyUserControl, MyUserControlToolboxItem and MyUserControlDesigner. You can comment Designer and/or ToolboxItem attributes and close all designers and clean and rebuild the solution and drop an instance of the control on the form to see how it works.
using System.CodeDom;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing.Design;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Forms.Design;
[Designer(typeof(MyUserControlDesigner))]
[ToolboxItem(typeof(MyUserControlToolBoxItem))]
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
}
public string MyTextProperty { get; set; } = "Something";
}
public class MyUserControlToolBoxItem : ToolboxItem
{
protected override IComponent[] CreateComponentsCore(IDesignerHost host)
{
IComponent[] componentsCore = base.CreateComponentsCore(host);
if (componentsCore != null && componentsCore.Length > 0
&& componentsCore[0] is MyUserControl)
(componentsCore[0] as MyUserControl)
.MyTextProperty = "Something else"; ;
return componentsCore;
}
}
public class MyUserControlDesigner : ControlDesigner
{
public override void InitializeNewComponent(IDictionary defaultValues)
{
base.InitializeNewComponent(defaultValues);
var component = Control;
var eventBindingService = (IEventBindingService)this.GetService(
typeof(IEventBindingService));
var componentChangeService = (IComponentChangeService)this.GetService(
typeof(IComponentChangeService));
var designerHostService = (IDesignerHost)GetService(typeof(IDesignerHost));
var rootComponent = designerHostService.RootComponent;
var uiService = (IUIService)GetService(typeof(IUIService));
var designerTransaction = (DesignerTransaction)null;
try
{
designerTransaction = designerHostService.CreateTransaction();
var e = TypeDescriptor.GetEvents(rootComponent)["Load"];
if (e != null)
{
var methodName = "";
var eventProperty = eventBindingService.GetEventProperty(e);
if (eventProperty.GetValue(rootComponent) == null)
{
methodName = eventBindingService
.CreateUniqueMethodName(rootComponent, e);
eventProperty.SetValue(rootComponent, methodName);
}
else
methodName = (string)eventProperty.GetValue(rootComponent);
var code = this.GetService(typeof(CodeTypeDeclaration))
as CodeTypeDeclaration;
CodeMemberMethod method = null;
var member = code.Members.Cast<CodeTypeMember>()
.Where(x => x.Name == methodName).FirstOrDefault();
if (member != null)
{
method = (CodeMemberMethod)member;
method.Statements.Add(
new CodeSnippetStatement($"{Control.Name}" +
$".MyTextProperty = \"Even something else!\";"));
}
componentChangeService.OnComponentChanged(rootComponent,
eventProperty, null, null);
eventBindingService.ShowCode(rootComponent, e);
}
designerTransaction.Commit();
}
catch (System.Exception ex)
{
if (designerTransaction != null)
designerTransaction.Cancel();
uiService.ShowError(ex);
}
}
}

Dynamically showing a text box created in another class, on a win form in C#

My intension is to create a dynamic textbox in Form1. I have a Class 'Form1' and a Class 'SplBox'. I have declared a dynamic textbox in class 'SplBox' & passed a string to it. All I want is to call this dynamic textbox in class 'Form1' & display it in Form1 main form. In my above code a new form is getting opened up & then in this new form the dynamic textbox is shown - which I do not want
namespace TxtClassRun
{
public partial class Form1 : Form
{
SplBox s1 = new SplBox();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// show the dynamic text box in Form1
s1.settxtbox();
s1.Show(); // opening another window. I want it to be in "Form1"
}
}
//New Class
public partial class SplBox : Form
{
//Global declarations
TextBox t2 = new TextBox();
public void settxtbox()
{
t2.Text = "Hello World";
Controls.Add(t2);
}
}
}
Try this,
public partial class SplBox : Form
{
//Global declarations
TextBox t2 = new TextBox();
private Form TempOwnerForm;
public SplBox(Form TempOwnerForm) {
this.TempOwnerForm = TempOwnerForm;
}
public Form OwnerForm { get { return TempOwnerForm; } set { this.TempOwnerForm = value; } }
public void settxtbox()
{
t2.Text = "Hello World";
TempOwnerForm.Controls.Add(t2);
}
}
Hope helps,

Categories