How to display the MonthCalendar control on top of Panels? - c#

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.

Related

Exposing VisualOffsets property

I am making an application in C# WPF and need the location of an object that I added to a panel. While debugging I found the VisualOffset property of the object that gives me the relative position. I just can't get the value from the code.
What I would like to do is (though it is not possible):
var display = new Display(); // This is a class that inhereit UserControl
.
.
// At some point when display is added to a panel
var position = display.VisualOffset; // This property is not accessible
So how can I get the relative position of an object?
Use TranslatePoint method of the Display instance. Set the parent control as a target. The code below will give you coordinates of display on its parent. If the container is further down the visual tree then you have to find a parent of a parent.
In my sample I'm finding that on the parent. I'm doing that on button click and then return the results as a string to a text box - purely for simplicity sake. But the idea is the same wherever you use it:
private void Button_Click(object sender, RoutedEventArgs e)
{
var parent = display.Parent as UIElement;
var location = display.TranslatePoint(new Point(0, 0), parent);
this.myTextBox.Text = $"x: {location.X}, y: {location.Y}";
}
display is of course an instance of the Display user control.

Creating a MouseEnter Event for every Button in a window

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.

How to disallow interaction on a view behind uipopovercontroller

I have a UIPopoverController that I am using and I have two buttons each displays a popup when clicked. However, I do not want the popup to be displayed at the same time - meaning I do not want the user to be able to press the one button and while the popup is displayed be able to press the other button. It seems like I have tried everything - disabling the user interaction on the buttons, hiding the view behind the pop up, using passthrough views for the pop and more. None of it works! The disabling of the user interaction seems to work for the most part but then stops disallowing the user to interact with the button and causes the application to crash...
popupView.PassthroughViews = new UIView[]{this.View.Superview, this.View, this.Gray}; //gray is another view that sits under the view that calls the popup
this.View.UserInteractionEnabled = false;
this.PositiveMeterBtn.UserInteractionEnabled = false;
this.View.Hidden = true;
My UIPopoverController is declared at the class level and I have even done code like this:
if(popupView != null)
return;
I still get multiple popups. I am using mono touch/xamarin - is this a bug with xamarin or an ios issue? Am I handling this in the correct manner?
I haven't worked with Xamarin before, but what's worked for me in native Objective-C is
[controller setModalInPopover:YES];
where controller is the view controller displayed within the popover.
From the UIViewController class reference:
#property(nonatomic, readwrite, getter=isModalInPopover) BOOL modalInPopover
The default value of this property is NO. Setting it to YES causes an owning popover controller to disallow interactions outside this view controller while it is displayed.
You can either make the popover modal but if it doesn't contain content that is meant to be modal, you shouldn't block the user.
Usually the better option is to make two helper methods and place them for instance in your app delegate. The methods take care that an existing popover is dismissed if another one is to be shown. This way you will have a maximum of on UIPopoverController and don't have to worry about dismissal.
/// <summary>
/// Shows a popover.
/// </summary>
/// <param name='controllerToShow'>the controller to show in the popover</param>
/// <param name='showFromRect'>the rectangle to present the popover from. Not used if showFromItem is specified.</param>
/// <param name='showInView'>the view the popover is hosted in</param>
/// <param name='showFromItem'>the bar button item the popover gets presented from.</param>
/// <param name='popoverContentSize'>the content size of the popover</param>
/// <param name='animated'>If set to <c>true</c>, animated the popover</param>
/// <param name='arrowDirection'>the allowed arrow directions</param>
/// <param name='onDismiss'>callback if the popover gets dismissed. Careful that the object that owns the callback doesn't outlive the popover controller to prevent uncollectable memory.</param>
public static void ShowPopover(UIViewController controllerToShow, RectangleF showFromRect, UIView showInView, UIBarButtonItem showFromItem, SizeF popoverContentSize, bool animated = true, UIPopoverArrowDirection arrowDirection = UIPopoverArrowDirection.Any, EventHandler onDismiss = null)
{
if(AppDelegateBase.popoverController != null)
{
AppDelegateBase.DismissPopover(false);
}
if(showFromItem == null && showFromRect.IsEmpty)
{
// Nothing to attach the popover to.
return;
}
popoverController = new UIPopoverController(controllerToShow);
if(!popoverContentSize.IsEmpty)
{
popoverController.SetPopoverContentSize(popoverContentSize, false);
}
if(onDismiss != null)
{
popoverController.DidDismiss += onDismiss;
}
// Send a notification that a popover will be presented.
NSNotificationCenter.DefaultCenter.PostNotificationName("WillPresentPopover", popoverController);
if(showFromItem != null)
{
popoverController.PresentFromBarButtonItem(showFromItem, arrowDirection, animated);
}
else
{
popoverController.PresentFromRect(showFromRect, showInView, arrowDirection, animated );
}
}
/// <summary>
/// Dismisses the popover presented using ShowPopover().
/// </summary>
/// <param name='animated'>If set to <c>true</c>, animates the dismissal</param>
public static void DismissPopover(bool animated = false)
{
if(popoverController != null)
{
popoverController.Dismiss(animated);
}
AppDelegateBase.popoverController = null;
}
private static UIPopoverController popoverController;
One thing you might try is using the method
-(BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
And in that method check if one of your popover view controller's is on screen.
if (popupView.view.window) {
return NO;
} else {
return YES;
}

C# ContextMenuStrip sub menu properties

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;
}

How change the color of SelectedItem in CheckedListBox in WindowsForms?

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);
}
}
}
}

Categories

Resources