Can anyone tell me how to get at the properties for the submenu in a ContextMenuStrip?
I know I can create a form and drop a context menu strip onto it. If I then add some items to the strip:
List item
Pens
-- Red
-- Blue
Markers
-- Green
-- Orange
I then write the following code:
public partial class Form3 : Form
{
public Form3()
{
InitializeComponent();
this.contextMenuStrip1.AutoSize = false;
this.contextMenuStrip1.Height = 300;
this.contextMenuStrip1.Width = 150;
}
/// <summary>
/// Handles the MouseClick event of the Form1 control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
private void Form3_MouseClick_1(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
Point pt = this.PointToScreen(e.Location);
this.contextMenuStrip1.Show(pt);
}
}
}
The Top level menu showing Pens and Markers will be on a non autosized strip 150 * 300 but if i hover over Pens to get the sub menu, Red and Blue, this submenu will show up on a autosized strip!
How do I get at the sub menu properties so I can set it's height?
For your question about
How do I get at the sub menu properties so I can tell it what height I
want it!
Use Items:
ContextMenuStrip1.Items[0].Height=200;
and for any sub-itmes of items[0]:
foreach(ToolStripItem item in (ContextMenuStrip1.Items[0] as ToolStripDropDownItem).DropDownItems)
{
item.AutoSize=false;
item.Height=200;
}
Related
I am trying to reuse NumberBoxes for a GridView because having the NumberBoxes embedded directly in the GridView data template causes undesirable behavior, while reusing them does not. The problem is that I keep getting exceptions. They say "No installed components were detected" on the following line (templateRoot.FindName("NumberBox") as GridViewItem).Content = item.NumberBox; in this context
/// <summary>
/// The callback for updating a container in the GridView named CardGridView.
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
private void UpdateGridViewContainer(ListViewBase sender, ContainerContentChangingEventArgs args)
{
if (args.Phase == 1)
{
Grid templateRoot = args.ItemContainer.ContentTemplateRoot as Grid;
CardItem item = args.Item as CardItem;
(templateRoot.FindName("NumberBox") as GridViewItem).Content = item.NumberBox;
TypedEventHandler<NumberBox, NumberBoxValueChangedEventArgs> handler =
(box, args) =>
{
if (!double.IsNaN(args.NewValue))
{
_viewModel.ChangeCount(args, item);
}
};
item.SetHandler(handler);
}
}
The exception is thrown when the Page that contains the GridView is left and renavigated to. I have tried nulling out the NumberBoxes when the page is left, but that did not work. Well, it appeared to before the issue cropped up again.
This is the code that nulls out the NumberBoxes
/// <summary>
/// Creates new NumberBoxes for when this Page is loaded again.
/// </summary>
private void ResetNumberBoxes()
{
foreach (CardItem card in CardGridView.Items.Cast<CardItem>())
{
card.ResetNumberBox();
}
CardGridView.ItemsSource = null;
CardGridView.Items.Clear();
}
ResetNumberBox is just setting the NumberBox to null and assigning a new one.
The exception details
System.Runtime.InteropServices.COMException
HResult=0x800F1000
Message=No installed components were detected. (0x800F1000)
Source=WinRT.Runtime
StackTrace:
at WinRT.ExceptionHelpers.<ThrowExceptionForHR>g__Throw|20_0(Int32 hr)
at ABI.Microsoft.UI.Xaml.Controls.IContentControlMethods.set_Content(IObjectReference _obj, Object value)
An update. I have removed the GridViewItem control from the DataTemplate and tried doing the following with the same result
CardItem item = args.Item as CardItem;
Grid.SetColumn(item.NumberBox, 1);
item.NumberBox.HorizontalAlignment = HorizontalAlignment.Center;
item.NumberBox.VerticalAlignment = VerticalAlignment.Center;
(templateRoot.FindName("GridViewTemplate") as Grid).Children.Add(item.NumberBox);
I also examined a heap dump right before the line that throws, and there was only one instance of the Grid, and the NumberBox had a parent of null.
How can I display the MonthCalendar on top similar to the DateTimePickerdrop down? I have a
a custom control (TextBox and Button) that displays the MonthCalendar dynamically when clicked.
I was able to get it in front of the controls with the panel but not over the panel. Image below;
private void btn_Click(object sender, EventArgs e)
{
if (mc.Parent == null)
{
this.Parent.Controls.Add(mc);
mc.Location = new Point(this.Location.X, this.Location.Y + this.Height);
mc.BringToFront();
}
else
{
mc.Show();
}
}
The drop-down calendar on a DateTimePicker is a floating window, as is the drop-down list on a ComboBox. The MonthCalendar is just a regular control so, just like any other control, it cannot be displayed outside the bounds of its parent. If you want it displayed over a form and outside the bounds of a Panel then you'd need to make its parent the form, rather than the Panel. If you want it to be displayed outside the bounds of the form too then you'd need to create a new, borderless form and make that the control's parent.
Here is a method you can use to move a child control from one parent to another without changing its absolute position on screen:
/// <summary>
/// Moves a child control from its current parent to a new parent while maintaining the same absolute location.
/// </summary>
/// <param name="child">
/// The child control to move.
/// </param>
/// <param name="newParent">
/// The new parent to move the child control to.
/// </param>
private void ChangeParent(Control child, Control newParent)
{
var screenLocation = child.PointToScreen(Point.Empty);
child.Parent = null;
child.Location = newParent.PointToClient(screenLocation);
child.Parent = newParent;
}
In your case, you probably want to call that like so:
ChangeParent(mc, this);
You may need to call BringToFront on the child control afterwards, depending on your z-order.
Note that you can also just add the MonthCalendar to the form in the designer and then change its Location in the properties window to get it in the right place.
I've been working on an application months ago, my friend and i wanted to share this application with other friends, and i need to display some help to make the application easier because it was designed only for both of us.
The idea that came out is to display help on a text Block every time a hover event is popped from a button. So we added a textBlock. Now the problem that we still facing is how to create the Hover Event for every button in our Main Window, there are a lots of buttons in this window, So we can't add an event to every button in the XAML code.
What i am expecting from this answer is a way to add Hover Event to all buttons in the main window Programmatically ?
EDIT: after some googling and help, i can do the following :
foreach (UIElement btn in GeneralMenuGrid.Children)
{
if (btn is Button)
{
Button currentButton = (Button)btn;
currentButton.Content = "test";
}
}
This is just a test that will allow all the buttons in the GeneralMenuGrid control to have a content : test, now the problem again is that i have nested controls in this grid, how can i reach them?
EDIT : after years of goggling i got to loop through all the buttons in my window with this :
public static void EnumVisuals(Visual argVisual, Window currentWindow)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(argVisual); i++)
{
Visual childVisual = (Visual) VisualTreeHelper.GetChild(argVisual, i);
if (childVisual is Button)
{
var button = childVisual as Button;
button.MouseEnter += AllButtonsOnMouseEnter;
}
EnumVisuals(childVisual, currentWindow);
}
}
now in the AllButtonsOnMouseEnter function, i can't access a button, i made it public... i can't access it from this class, how can i send the window with the event arguments?
You wrote, "there are a lots of buttons in this window, so we can't add an event to every button in the XAML code." But you can - just add a style that applies to all buttons:
<Style TargetType="{x:Type Button}">
<EventSetter Event="MouseEnter" Handler="Button_MouseEnter"/>
</Style>
I don't know how you intend to get the help text relevant to each Button, but it's easy to store it in the Button's Tag:
<Button Tag="Instantly move from one place to another.">
Teleport
</Button>
Then write an event handler that shows the help in your TextBlock:
private void Button_MouseEnter(object sender, MouseEventArgs e)
{
Button button = sender as Button;
textblock_that_shows_help.Text = button.Tag;
}
I've created an extension method that does this, adapted from here: Find all controls in WPF Window by type
Put this class somewhere in your project:
public static class VisualTreeSearch
{
/// <summary>
/// Finds all elements of the specified type in the <see cref="System.Windows.DependencyObject"/>'s visual tree using a breadth-first search.
/// </summary>
/// <typeparam name="T">The type of element to search for.</typeparam>
/// <param name="root">The object to search in.</param>
/// <returns>A list of elements that match the criteria.</returns>
public static IEnumerable<T> Find<T>(this DependencyObject root) where T : DependencyObject
{
return root.Find<T>(false, true);
}
/// <summary>
/// Finds all elements of the specified type in the <see cref="System.Windows.DependencyObject"/>'s visual tree.
/// </summary>
/// <typeparam name="T">The type of element to search for.</typeparam>
/// <param name="root">The object to search in.</param>
/// <param name="depthFirst">True to do a depth-first search; false to do a breadth-first search</param>
/// <param name="includeRoot">True to include the root element in the search; false to exclude it</param>
/// <returns>A list of elements that match the criteria.</returns>
public static IEnumerable<T> Find<T>(this DependencyObject root, bool depthFirst, bool includeRoot) where T : DependencyObject
{
if (includeRoot)
{
var depRoot = root as T;
if (depRoot != null)
yield return depRoot;
}
var searchObjects = new LinkedList<DependencyObject>();
searchObjects.AddFirst(root);
while (searchObjects.First != null)
{
var parent = searchObjects.First.Value;
var count = VisualTreeHelper.GetChildrenCount(parent);
var insertAfterNode = depthFirst ? searchObjects.First : searchObjects.Last;
for (int i = 0; i < count; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(parent, i);
var depChild = child as T;
if (depChild != null)
yield return depChild;
insertAfterNode = searchObjects.AddAfter(insertAfterNode, child);
}
searchObjects.RemoveFirst();
}
}
}
To use the extension method, write the following in your window class (as an example). This code loops through all children, grandchildren, etc. of this (which should be your Window in this case) and finds all Button elements.
foreach (var button in this.Find<Button>())
{
button.MouseEnter += button_MouseEnter;
}
...
private void button_MouseEnter(object sender, MouseEventArgs e)
{
// Do stuff
}
after a lot of googling and chat help... i finally did it, maybe other will be interested this is how i proceeded :
i created a static recursive function that will get all the buttons in the window:
public static void EnumVisuals(Visual argVisual, Button toModifyButton)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(argVisual); i++)
{
Visual childVisual = (Visual) VisualTreeHelper.GetChild(argVisual, i);
if (childVisual is Button)
{
var button = childVisual as Button;
button.MouseEnter += (sender, eventArgs) =>
{
toModifyButton.Content = "Get the Help text from database if you want";
};
}
EnumVisuals(childVisual, toModifyButton);
}
}
why do you send a Button :
i need to write the help in a button, and the only way i found to access it's content property is to send it via this function and of course make it public.
Hope you'll find this helpfull.
On a ZedGraph pane, it is possible to set a CurveItem as "selected".
zedGraphControl.GraphPane.CurveList[0].IsSelected = true;
zedGraphControl.Refresh();
This will change its color to Color.Gray as far as I can see.
Is it possible to change this selected-state color?
I don't know of such a property but you can accomplish this by manually overriding the MouseClick event of the ZedGraphControl and set the color of the "selected" CurveItem, something like:
private void zedGraphControl1_MouseClick(object sender, MouseEventArgs e)
{
foreach (var curve in zedGraphControl1.GraphPane.CurveList)
{
curve.Color = Color.Black;
}
CurveItem nearestItem;
int nearestPoint;
zedGraphControl1.GraphPane.FindNearestPoint(e.Location, out nearestItem, out nearestPoint);
if (nearestItem != null)
{
nearestItem.Color = Color.Red;
}
zedGraphControl1.Refresh();
}
UPDATE: Looking at the source code of http://www.opensourcejavaphp.net/csharp/zedgraph/Line.cs.html and http://www.opensourcejavaphp.net/csharp/zedgraph/Selection.cs.html it seems that Line.DrawCurve is using static property Selection.Line. Without modifying source it would be hard to change this behaviour.
Part of Line.cs:
public void DrawCurve( Graphics g, GraphPane pane, CurveItem curve, float scaleFactor )
{
Line source = this;
if ( curve.IsSelected )
source = Selection.Line;
Selection.cs:
/// The <see cref="Line" /> type to be used for drawing "selected"
/// <see cref="LineItem" /> and <see cref="StickItem" /> types
/// </summary>
public static Line Line = new Line( Color.Gray );
The selected line is a static property, but NOT read-only. One can change the format by resetting the Selection.Line property:
public Form1()
{
InitializeComponent();
ZedGraph.Selection.Line.Width = 3;
ZedGraph.Selection.Line.Color = Color.Red;
...
}
After resetting the selection line, all selected lines will draw as specified.
I want to change the color of the items that are chedked in the CheckedListBox in C# WindowsForms.
Can any one help me to solve this problem!
This should get you started. I've subclassed a CheckedListBox and overridden the drawing event. The result is all checked items in the list are drawn with a red background.
From playing around with this, if you want the area behind the checkbox to be a different colour as well, use e.Graphics.FillRectangle before calling base.OnDrawItem.
class ColouredCheckedListBox : CheckedListBox
{
protected override void OnDrawItem(DrawItemEventArgs e)
{
DrawItemEventArgs e2 =
new DrawItemEventArgs
(
e.Graphics,
e.Font,
new Rectangle(e.Bounds.Location, e.Bounds.Size),
e.Index,
e.State,
e.ForeColor,
this.CheckedIndices.Contains(e.Index) ? Color.Red : SystemColors.Window
);
base.OnDrawItem(e2);
}
}
Thanks Jon that got me on the right path as I had the same desire: to have the item's text color be different for each of the 3 states of the checkbox.
I came up with this subclass of the CheckedListBox. It changes the items text, not the background color. It lets the 3 colors be set by the user at design time or in code of course.
It also fixes a problem I had where I got an error when viewing the control in the designer. I also had to overcome a problem I think would have happened in your solution where if the item is selected the base.OnDrawItem method obliterates the color choices set in the overridden OnDrawItem method. I did this at the expense of the selected item no longer having a colored background by removing the part of e.State that says it is selected so that in the base.OnDrawItem it is not made to be a selected item look and feel. This is ok though I think since the user will see the focus rectangle still which indicates which is selected.
Hopefully this may be useful to others. I didn't find much for a cohesive solution (even just a complete OnDrawItem method) when looking on the net.
using System;
using System.Windows.Forms;
using System.Drawing;
namespace MyNameSpace
{
/// <summary>
/// This is a CheckedListBox that allows the item's text color to be different for each of the 3 states of the corresponding checkbox's value.
/// Like the base CheckedListBox control, you must handle setting of the indeterminate checkbox state yourself.
/// Note also that this control doesn't allow highlighting of the selected item since that obscures the item's special text color which has the special meaning. But
/// the selected item is still known to the user by the focus rectangle it will have surrounding it, like usual.
/// </summary>
class ColorCodedCheckedListBox : CheckedListBox
{
public Color UncheckedColor { get; set; }
public Color CheckedColor { get; set; }
public Color IndeterminateColor { get; set; }
/// <summary>
/// Parameterless Constructor
/// </summary>
public ColorCodedCheckedListBox()
{
UncheckedColor = Color.Green;
CheckedColor = Color.Red;
IndeterminateColor = Color.Orange;
}
/// <summary>
/// Constructor that allows setting of item colors when checkbox has one of 3 states.
/// </summary>
/// <param name="uncheckedColor">The text color of the items that are unchecked.</param>
/// <param name="checkedColor">The text color of the items that are checked.</param>
/// <param name="indeterminateColor">The text color of the items that are indeterminate.</param>
public ColorCodedCheckedListBox(Color uncheckedColor, Color checkedColor, Color indeterminateColor)
{
UncheckedColor = uncheckedColor;
CheckedColor = checkedColor;
IndeterminateColor = indeterminateColor;
}
/// <summary>
/// Overriden draw method that doesn't allow highlighting of the selected item since that obscures the item's text color which has desired meaning. But the
/// selected item is still known to the user by the focus rectangle being displayed.
/// </summary>
/// <param name="e"></param>
protected override void OnDrawItem(DrawItemEventArgs e)
{
if (this.DesignMode)
{
base.OnDrawItem(e);
}
else
{
Color textColor = this.GetItemCheckState(e.Index) == CheckState.Unchecked ? UncheckedColor : (this.GetItemCheckState(e.Index) == CheckState.Checked ? CheckedColor : IndeterminateColor);
DrawItemEventArgs e2 = new DrawItemEventArgs
(e.Graphics,
e.Font,
new Rectangle(e.Bounds.Location, e.Bounds.Size),
e.Index,
(e.State & DrawItemState.Focus) == DrawItemState.Focus ? DrawItemState.Focus : DrawItemState.None, /* Remove 'selected' state so that the base.OnDrawItem doesn't obliterate the work we are doing here. */
textColor,
this.BackColor);
base.OnDrawItem(e2);
}
}
}
}