Adding a collapsible panel in outlook - c#

I'm writing an outlook add-in and I'm looking for a way to make a panel docked on the right of my screen collapsible. At the moment the panel is either displayed or removed. You can also scale it but that's not what I'm looking for. I already tried adding 2 buttons which change the width of my panel onclick but the result is that my panel can't get smaller than about 60px in width and the title is still there. Here is the code I use to add my pane:
Microsoft.Office.Tools.CustomTaskPane ctp;
private HistoryPane ctrl;
string title = "Task History";
ctrl = new HistoryPane(mailItem);
ctp = Globals.ThisAddIn.CustomTaskPanes.Add(ctrl, title);
ctp.Visible = true;
ctp.Width = 460;
ctp.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionRight;
Any help to either remove the title, make the panel thinner (about 25px), make it collapsible or all of them would be much appreciated.

here is solution below:
1 - Create a public method in your user control like below:
private Microsoft.Office.Tools.CustomTaskPane _ctp;
public void SetControl(ref Microsoft.Office.Tools.CustomTaskPane ctp)
{
_ctp = ctp;
}
2 - Add any button to Expend and Minimize in your User Control and put below codes on Minimize button on click event:
private void btnMinimize_Click(object sender, EventArgs e)
{
_ctp.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionTop;
_ctp.Height = 50;
}
3 - After your code above use bold line code below:
Microsoft.Office.Tools.CustomTaskPane ctp;
private HistoryPane ctrl;
string title = "Task History";
ctrl = new HistoryPane(mailItem);
ctp = Globals.ThisAddIn.CustomTaskPanes.Add(ctrl, title);
ctp.Visible = true;
ctp.Width = 460;
ctp.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionRight;
ctrl.SetControl(ref ctp);
Hope this will work.

Related

Expander menu in C #

I am trying to reproduce the operation of the Control Expander WPF, or as shown in the menu of Outlook, Vertical Web Menu etc., since in WindowsForms this control does not exist. Here I leave the sample code: Menu_Expader.zip link GoogleDrive.
I have managed to do it using the following controls:
Panels
FlowLayoutPanel
1 Time Control
Button Vectors
Labels Vectors ...
This works perfectly, but it happens that to each panel I must establish a
Maximum Size and Minimum Size therefore every time I add an item inside I must modify the size of the panel where I add it, and the item are very close to each other is a bit annoying for the user's vision.
Example this is what I currently have:
EDIT
Code Sample:
// The state of an expanding or collapsing panel.
private enum ExpandState
{
Expanded,
Expanding,
Collapsing,
Collapsed,
}
// The expanding panels' current states.
private ExpandState[] ExpandStates;
// The Panels to expand and collapse.
private Panel[] ExpandPanels;
// The expand/collapse buttons.
private Button[] ExpandButtons;
// Initialize.
private void Form1_Load(object sender, EventArgs e)
{
// Initialize the arrays.
ExpandStates = new ExpandState[]
{
ExpandState.Expanded,
ExpandState.Expanded,
ExpandState.Expanded,
};
ExpandPanels = new Panel[]
{
panModule1,
panModule2,
panModule3,
};
ExpandButtons = new Button[]
{
btnExpand1,
btnExpand2,
btnExpand3,
};
// Set expander button Tag properties to give indexes
// into these arrays and display expanded images.
for (int i = 0; i < ExpandButtons.Length; i++)
{
ExpandButtons[i].Tag = i;
ExpandButtons[i].Image = Properties.Resources.expander_down;
}
}
// Start expanding.
private void btnExpander_Click(object sender, EventArgs e)
{
// Get the button.
Button btn = sender as Button;
int index = (int)btn.Tag;
// Get this panel's current expand
// state and set its new state.
ExpandState old_state = ExpandStates[index];
if ((old_state == ExpandState.Collapsed) ||
(old_state == ExpandState.Collapsing))
{
// Was collapsed/collapsing. Start expanding.
ExpandStates[index] = ExpandState.Expanding;
ExpandButtons[index].Image = Properties.Resources.expander_up;
}
else
{
// Was expanded/expanding. Start collapsing.
ExpandStates[index] = ExpandState.Collapsing;
ExpandButtons[index].Image = Properties.Resources.expander_down;
}
// Make sure the timer is enabled.
tmrExpand.Enabled = true;
}
// The number of pixels expanded per timer Tick.
private const int ExpansionPerTick = 7;
// Expand or collapse any panels that need it.
private void tmrExpand_Tick(object sender, EventArgs e)
{
// Determines whether we need more adjustments.
bool not_done = false;
for (int i = 0; i < ExpandPanels.Length; i++)
{
// See if this panel needs adjustment.
if (ExpandStates[i] == ExpandState.Expanding)
{
// Expand.
Panel pan = ExpandPanels[i];
int new_height = pan.Height + ExpansionPerTick;
if (new_height >= pan.MaximumSize.Height)
{
// This one is done.
new_height = pan.MaximumSize.Height;
}
else
{
// This one is not done.
not_done = true;
}
// Set the new height.
pan.Height = new_height;
}
else if (ExpandStates[i] == ExpandState.Collapsing)
{
// Collapse.
Panel pan = ExpandPanels[i];
int new_height = pan.Height - ExpansionPerTick;
if (new_height <= pan.MinimumSize.Height)
{
// This one is done.
new_height = pan.MinimumSize.Height;
}
else
{
// This one is not done.
not_done = true;
}
// Set the new height.
pan.Height = new_height;
}
}
// If we are done, disable the timer.
tmrExpand.Enabled = not_done;
}
I want to get a result similar to this - Bootstrap Menu Accordion:
 
Imitate that operation panels expand according to the quantity of item that it contains as long as it does not protrude from the screen, in which case it will show the scroll bar. I know there are software that provide custom controls like DVexpress, DotNetBar Suite among others, but they are Licensed Software I do not want to use it illegally pirate. Can you help me optimize it or create it in another way?
Environment: Visual Studio 2010 & .NET NetFramework 4.
The original question I made it in StackOverFlow in Spanish.
Modulo (Module)
Menu Principal (Main menu)
Mantenimientos (Maintenance)
Procesos (Processes)
Consultas (Queries)
Reportes (Reports)
Note: If someone speaks Spanish and English and can do a better translation, please edit the question. (Excuse the advertising on the image, I recorded the screen with a software trial version).

Removing controls from a windows form if another menu strip option is clicked

I have a menu strip in place that when clicked upon, adds controls and shows them on the windows application I am making. However, when I try to click on another option and attempt to hide the previous controls shown, it does not hide itself but merely stays on the screen and the datagridview is shown on top of it. I tried the Hide() method but that does not appear to be working.
Here is my code (the AddControls method I made, where it is called, and the HideAllControls method I also made)
Add Controls -
private void AddControls()
{
// begin household head controls
Label householdHeadLbl = new Label()
{
Name = "lbl_householdHead",
Text = "Household Head"
};
householdHeadLbl.Font = new Font(householdHeadLbl.Font.FontFamily, 12);
householdHeadLbl.Location = new Point(86, 75);
householdHeadLbl.Size = new Size(130, 24);
////////////////////////////////////////////
TextBox houseHoldHeadTextBox = new TextBox()
{
Name = "txtBox_householdHead"
};
houseHoldHeadTextBox.Font = new Font(houseHoldHeadTextBox.Font.FontFamily, 12);
houseHoldHeadTextBox.Location = new Point(220, 72);
houseHoldHeadTextBox.Size = new Size(154, 24);
// add the controls
// household head controls
Controls.Add(householdHeadLbl);
Controls.Add(houseHoldHeadTextBox);
}
(There are more controls but I went past the 30000 character limit)
Menu Strip Insert Member Click -
private void MenuInsertMember_Click(object sender, EventArgs e)
{
AddControls();
}
HideAllControls -
private void HideAllControls(Control ctrl)
{
foreach (Control c in Controls)
{
if (c is TextBox || c is Label)
{
c.Hide();
}
else
{
break;
}
}
}
Menu Strip View Click -
private void MenuViewMembers_Click(object sender, EventArgs e)
{
// hide any controls left that may be left over from another option
HideAllControls(this);
}
I included a screenshot to help show/explain what I am encountering.
Insert screenshot - http://imgur.com/zGBY3b4
View screenshot - http://imgur.com/yecBbiw
Any help would be appreciated.
Thanks!

Tool tip balloon is not showing for controls in win forms

I have a windows form application where some controls are hidden at first and visible on some condition.
Sometimes tool tip balloon is not visible.
I have below code in constructor,
ToolTip toolTipBalloon;
toolTipBalloon.AutoPopDelay = 15000;
toolTipBalloon.InitialDelay = 1500;
toolTipBalloon.IsBalloon = true;
toolTipBalloon.ReshowDelay = 100;
toolTipBalloon.ToolTipTitle = "Setting";
toolTipBalloon.Popup += new System.Windows.Forms.PopupEventHandler(this.toolTipBalloon_Popup);
In event handler:
private void toolTipBalloon_Popup(object sender, PopupEventArgs e)
{
// Set title of tooltip to control's accessible name or text
Control ctrl = e.AssociatedControl;
if (!String.IsNullOrEmpty(ctrl.AccessibleName))
toolTipBalloon.ToolTipTitle = ctrl.AccessibleName;
else if (!String.IsNullOrEmpty(ctrl.Text))
toolTipBalloon.ToolTipTitle = ctrl.Text;
}
You'll have to assign the tooltip to the control at some point.
toolTipBalloon.SetToolTip(ctrl, "Message");
You can also add multiple controls with diffrent messages to the same tooltip.
toolTipBalloon.SetToolTip(btnStart, "Start the thingy!");
toolTipBalloon.SetToolTip(lblSpeed, "You're going thiiiis fast.");
toolTipBalloon.SetToolTip(txtName, "Enter your super hero name.");

Links inside rich textbox?

I know that richtextboxes can detect links (like http://www.yahoo.com) but is there a way for me to add links to it that looks like text but its a link? Like where you can choose the label of the link? For example instead of it appearing as http://www.yahoo.com it appears as Click here to go to yahoo
edit: forgot, im using windows forms
edit: is there something thats better to use (as in easier to format)?
Of course it is possible by invoking some WIN32 functionality into your control, but if you are looking for some standard ways, check this post out:
Create hyperlink in TextBox control
There are some discussions about different ways of integration.
greetings
Update 1:
The best thing is to follow this method:
http://msdn.microsoft.com/en-us/library/f591a55w.aspx
because the RichText box controls provides some functionality to "DetectUrls". Then you can handle the clicked links very easy:
this.richTextBox1.LinkClicked += new System.Windows.Forms.LinkClickedEventHandler(this.richTextBox1_LinkClicked);
and you can simple create your own RichTextBox contorl by extending the base class - there you can override the methods you need, for example the DetectUrls.
Here you can find an example of adding a link in rich Textbox by linkLabel:
LinkLabel link = new LinkLabel();
link.Text = "something";
link.LinkClicked += new LinkLabelLinkClickedEventHandler(this.link_LinkClicked);
LinkLabel.Link data = new LinkLabel.Link();
data.LinkData = #"C:\";
link.Links.Add(data);
link.AutoSize = true;
link.Location =
this.richTextBox1.GetPositionFromCharIndex(this.richTextBox1.TextLength);
this.richTextBox1.Controls.Add(link);
this.richTextBox1.AppendText(link.Text + " ");
this.richTextBox1.SelectionStart = this.richTextBox1.TextLength;
And here is the handler:
private void link_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
System.Diagnostics.Process.Start(e.Link.LinkData.ToString());
}
I found a way which may not be the most elegant, but it's just a few lines of code and does the job. Namely, the idea is to simulate hyperlink appearance by means of font changes, and simulate hyperlink behavior by detecting what the mouse pointer is on.
The code:
public partial class Form1 : Form
{
private Cursor defaultRichTextBoxCursor = Cursors.Default;
private const string HOT_TEXT = "click here";
private bool mouseOnHotText = false;
// ... Lines skipped (constructor, etc.)
private void Form1_Load(object sender, EventArgs e)
{
// save the right cursor for later
this.defaultRichTextBoxCursor = richTextBox1.Cursor;
// Output some sample text, some of which contains
// the trigger string (HOT_TEXT)
richTextBox1.SelectionFont = new Font("Calibri", 11, FontStyle.Underline);
richTextBox1.SelectionColor = Color.Blue;
// output "click here" with blue underlined font
richTextBox1.SelectedText = HOT_TEXT + "\n";
richTextBox1.SelectionFont = new Font("Calibri", 11, FontStyle.Regular);
richTextBox1.SelectionColor = Color.Black;
richTextBox1.SelectedText = "Some regular text";
}
private void richTextBox1_MouseMove(object sender, MouseEventArgs e)
{
int mousePointerCharIndex = richTextBox1.GetCharIndexFromPosition(e.Location);
int mousePointerLine = richTextBox1.GetLineFromCharIndex(mousePointerCharIndex);
int firstCharIndexInMousePointerLine = richTextBox1.GetFirstCharIndexFromLine(mousePointerLine);
int firstCharIndexInNextLine = richTextBox1.GetFirstCharIndexFromLine(mousePointerLine + 1);
if (firstCharIndexInNextLine < 0)
{
firstCharIndexInNextLine = richTextBox1.Text.Length;
}
// See where the hyperlink starts, as long as it's on the same line
// over which the mouse is
int hotTextStartIndex = richTextBox1.Find(
HOT_TEXT, firstCharIndexInMousePointerLine, firstCharIndexInNextLine, RichTextBoxFinds.NoHighlight);
if (hotTextStartIndex >= 0 &&
mousePointerCharIndex >= hotTextStartIndex && mousePointerCharIndex < hotTextStartIndex + HOT_TEXT.Length)
{
// Simulate hyperlink behavior
richTextBox1.Cursor = Cursors.Hand;
mouseOnHotText = true;
}
else
{
richTextBox1.Cursor = defaultRichTextBoxCursor;
mouseOnHotText = false;
}
toolStripStatusLabel1.Text = mousePointerCharIndex.ToString();
}
private void richTextBox1_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && mouseOnHotText)
{
// Insert your own URL here, to navigate to when "hot text" is clicked
Process.Start("http://www.google.com");
}
}
}
To improve on the code, one could create an elegant way to map multiple "hot text" strings to their own linked URLs (a Dictionary<K, V> maybe). An additional improvement would be to subclass RichTextBox to encapsulate the functionality that's in the code above.
Many moons later there is a solution for .NET (Core), as of at least .NET 6.0 (possibly earlier) - for .NET Framework (whose latest and last version is 4.8) you'll still need one of the other solutions here:
The .Rtf property now recognizes RTF-format hyperlinks; e.g., the following renders as:
This is a true RTF hyperlink: Example Link
this.richTextBox1.Rtf = #"{\rtf1 This is a true RTF hyperlink:\line {\field{\*\fldinst HYPERLINK ""https://example.org""}{\fldrslt Example Link}}} }";
The standard RichTextBox control (assuming you are using Windows Forms) exposes a rather limited set of features, so unfortunately you will need to do some Win32 interop to achieve that (along the lines of SendMessage(), CFM_LINK, EM_SETCHARFORMAT etc.).
You can find more information on how to do that in this answer here on SO.

How do I remove a specific panel through event handling in my FlowlayoutPanel for my Windows Form Application?

For my C# Windows Form Application, I have created a flowlayoutpanel that contains several panels. Inside the panel, I have a button "Clear" for each and every single panel.
How do I write the event handler for the code for the button "Clear" such that once I have click the button, the panel would sort of be "Removed" from the flowlayoutpanel.
This is a short part of the code of the adding of panels to the flowlayoutpanel.
nFlowPanel.Controls.Add(createNotificationPanel());
nFlowPanel.Controls.Add(createNotificationPanel());
nFlowPanel.Controls.Add(createNotificationPanel());
nFlowPanel.Controls.Add(createNotificationPanelImpt());
nFlowPanel.Controls.Add(createNotificationPanelImpt());
and this is the code for the button "Clear"
Button btnClear = new Button
{
Text = "Clear",
Name = "btnClear",
Location = new Point(416, 17)
};
p.Controls.Add(btnClear);
btnClear.Click += new EventHandler(buttonClear_Click);
So what should i write in the following method to have the effect of removing e.g. the second panel that was added in the first part of code I have written?
void buttonClear_Click(object sender, EventArgs e)
{
throw new NotImplementedException();
}
EDIT
the code for creating my panel is
var p = new Panel
{
BorderStyle = BorderStyle.FixedSingle ,
Size = new Size(506,100),
Name = "notifyPanel"
};
and the code for creating my FlowLayoutPanel is
var nFlowPanel = new FlowLayoutPanel
{
FlowDirection = FlowDirection.TopDown,
WrapContents = false,
AutoScroll = true,
Size = new Size(530, 377),
Location = new Point(13, 145)
};
and the code for my button clear is
void buttonClear_Click(object sender, EventArgs e)
{
var button = (Control)sender;
var panel = button.Parent.Controls["notifyPanel"];
panel.Dispose();
}
however it gives the error
Object reference not set to an instance of an object.
on the panel.Dispose() line.
anyone can help?
The Controls.Remove() method is very dangerous, it doesn't dispose the control. Which will live on, moved to the so-called parking window, using up both Windows and managed resources. After a bit less than 10,000 times doing this it crashes your program when Windows is no longer willing to let you create any more windows.
Call the control's Dispose() method instead. That also automatically removes the control from its container.
void buttonClear_Click(object sender, EventArgs e)
{
var panel = nFlowPanel.Controls["notifyPanel"];
panel.Dispose();
}
You can do it like this:
nFlowPanel.Controls.Remove((sender as Button).Parent);
I will suggest you to use List for this. Before adding Panels in the FlowLayoutpanel, add them in the List. Then just remove the indexed panel from the flowlayoutpanel.
Panel pnlTemp = (panel)list[index];
nFlowPanel.Controls.Remove(pnlTemp);
To get the index of the button you have to add your buttons also to your list and after clicking any button, search the button in the list and get the index of the button where it is saved in the list. If my code is unclear, let me know. but I feel your task is that complex. I am not sure but this link may be of some help.
Hope it helps.

Categories