I have a "start" button with a custom image I have made. I haven't messed around with this part of C#.net, but I know a bit about VB.NET.
I've seen people have something like public void picturebox_MouseDown() and whatnot, but none seems to work. I am trying to change the image when a mouse event is given.
MouseDown would change the image to StartButtonDown
MouseUp would change the image to StartButtonUp
MouseEnter would change the image to StartButtonHover
MouseLeave would change the image to StartButtonUp
Is there something specific I should do, I've google'd this for about an hour and still haven't found anything to help me.
Here is something I wrote which is very similar to what you require.
using System;
using System.Drawing;
using System.Windows.Forms;
public partial class ImageButton : PictureBox
{
private Image _upImage, _downImage, _hoverImage;
[System.ComponentModel.Browsable(true),
System.ComponentModel.Category("Images")]
public Image UpImage
{
get { return _upImage; }
set
{
if (value != null)
{
_upImage = value;
this.Image = _upImage;
}
}
}
[System.ComponentModel.Browsable(true),
System.ComponentModel.Category("Images")]
public Image DownImage
{
get { return _downImage; }
set
{
if (value != null)
{
_downImage = value;
}
}
}
[System.ComponentModel.Browsable(true),
System.ComponentModel.Category("Images")]
public Image HoverImage
{
get { return _hoverImage; }
set
{
if (value != null)
{
_hoverImage = value;
}
}
}
public ImageButton()
{
InitializeComponent();
}
protected override void OnMouseDown(MouseEventArgs e)
{
if (DownImage != null)
this.Image = DownImage;
base.OnMouseDown(e);
}
protected override void OnMouseUp(MouseEventArgs e)
{
if (UpImage != null)
this.Image = UpImage;
base.OnMouseUp(e);
}
protected override void OnMouseEnter(EventArgs e)
{
if (HoverImage != null)
this.Image = HoverImage;
base.OnMouseEnter(e);
}
protected override void OnMouseLeave(EventArgs e)
{
if (UpImage != null)
this.Image = UpImage;
base.OnMouseLeave(e);
}
}
What I have done is inherrited from the standard PictureBoxto make an ImageButton. I have three properties for the Image to display with no mouse action (UpImage), the Image to display when the MouseDown event is triggered (DownImage), and the Image to display when the mouse is hovering over the control (HoverImage).
Note that you should add a check for the MouseUp and MouseLeave events. If I click on the image and drag the mouse away from the control, the control will go from the UpImage to the DownImage to the UpImage again because I have left the control (MouseLeave) even though my mouse is still down. You may desire that the DownImage remain displayed when the mouse leaves the control. Additionally, when the MouseUp event occurs, you should check if the mouse is still hovering over the control. If it is, you will want to display the HoverImage rather than the UpImage.
You could also check for which mouse button is used. Maybe you only want the images to change with left button clicks, not right or middle.
But this should get you started.
Related
I'm developing a Windows Desktop Application using C# in VS 2022 on Windows 10. I'm developing for a touch screen and want the UI to be very intuitive and give good feedback because the user(s) will likely be tech-averse. On several of the forms I'm using a PictureBox as a button because I like the visual effects better. I can get a nice "button pressed" effect by using the MouseDown and MouseUp events to change the border style of the PictureBox to Fixed3D (on mouse down) and back to None (on mouse up). The only issue is that the PictureBox image "blinks" when I do this, like the control is clearing the image out and reloading it or something.
My code is rather trivial, but I'll post it here anyway just in case:
private void Button_Down(object sender, MouseEventArgs e)
{
PictureBox pb = (PictureBox)sender;
pb.BorderStyle = BorderStyle.Fixed3D;
}
private void Button_Up(object sender, MouseEventArgs e)
{
PictureBox pb = (PictureBox)sender;
pb.BorderStyle = BorderStyle.None;
}
If you're open to solving your blinking problem another way, consider this reusable CustomButton class that lets you use your own custom image to depict the 3D pressed state. The icons are superimposed using the Text property and a custom font containing glyphs (making it easy to change their size and color). When the button is not pressed, system theme takes over or you could unset the UseVisualStyleBackColor property to additionally customize things like OnMouseHover.
CustomButton inherits from Buttonand has a PrivateFontCollection giving it access to a .ttf file containing glyphs. This particular flashlight-filter-history-favorite-search.ttf is one I designed for my own project using the Fontello open-source icon font generator.
public CustomButton()
{
UseCompatibleTextRendering = true;
TextAlign = ContentAlignment.MiddleCenter;
refCount++;
}
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
if (!DesignMode) initFont();
}
private void initFont()
{
if (privateFontCollection == null)
{
privateFontCollection = new PrivateFontCollection();
var path = Path.Combine(Path.GetDirectoryName(
Assembly.GetEntryAssembly().Location),
"Fonts",
"flashlight-filter-history-favorite-search.ttf");
privateFontCollection.AddFontFile(path);
var fontFamily = privateFontCollection.Families[0];
GlyphFontUp = new Font(fontFamily, 16F);
GlyphFontDown = new Font(fontFamily, 15F);
}
Font = GlyphFontUp;
ForeColor = GlyphColorUp;
}
PrivateFontCollection privateFontCollection = null;
public static Font GlyphFontUp { get; private set; } = null;
public static Font GlyphFontDown { get; private set; } = null;
public static Color GlyphColorUp { get; } = Color.Teal;
public static Color GlyphColorDown { get; } = Color.DarkCyan;
private static int refCount = 0;
protected override void Dispose(bool disposing)
{
if (disposing)
{
refCount--;
if (refCount == 0)
{
GlyphFontUp?.Dispose();
privateFontCollection?.Dispose();
}
}
base.Dispose(disposing);
}
When the mouse is down the button has an image, the icon is smaller, and the icon color changes. When the mouse comes up the image is removed and everything goes back to normal.
partial class CustomButton : Button
{
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
Image = new Bitmap(Resources.buttonDown, Size);
Font = GlyphFontDown;
ForeColor = GlyphColorDown;
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
Font = GlyphFontUp;
ForeColor = GlyphColorUp;
Image = null;
}
}
The buttonDown image is just something I drew myself. I'm pretty sure you could do better!
The CustomButton class can be swapped out in the MainForm.Designer.cs file.
// private System.Windows.Forms.Button customButton0;
private intuitive_buttons.CustomButton customButton0;
This code assigns the various icons to the buttons:
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
// Assign the icons to the buttons
customButton0.Text = "\uE800";
customButton1.Text = "\uE801";
customButton2.Text = "\uE802";
customButton3.Text = "\uE803";
customButton4.Text = "\uE804";
}
}
Hope this at least gives you a few ideas to try.
I'm trying to create new Button with custom event. It's new for me. I'm trying to call "Resize". I wanna create "switch" like in android.
I'm trying to do this like other existing controls. I've been doing this for 2 days and i still have nothing. I belive that you will able to help me :)
Here is my code:
public abstract class SwitchBase : Control
{
private Button first;
private Button second;
public SwitchBase()
{
InitializeMySwitch();
}
private void InitializeMySwitch()
{
Controls.Add(first = new Button());
Controls.Add(second = new Button());
//first
first.Text = "first";
//second
second.Text = "second";
second.Location = new System.Drawing.Point(first.Location.X + first.Width, first.Location.Y);
}
public delegate void ChangedEventHandler(object source, EventArgs args);
public event ChangedEventHandler Changed;
protected virtual void OnSwitchChanged()
{
if (Changed != null)
Changed(this, EventArgs.Empty);
}
public delegate void ResizeEventHandler(object source, EventArgs args);
public event ResizeEventHandler Resize;
protected virtual void OnResize()
{
Resize(this, EventArgs.Empty);
}
}
public class Switch : SwitchBase
{
public Switch()
{
}
protected override void OnSwitchChanged()
{
base.OnSwitchChanged();
}
protected override void OnResize()
{
base.OnResize();
}
}
In another button I change the size of my switch
From reading your code, I gather that by "call Resize" you mean to raise the event. What you are doing is correct... although it should be noted that by the default event implementation, it will be null if there are no subscribers...
In fact, another thread could be unsubscribing behind your back. Because of that the advice is to take a copy.
You can do that as follows:
var resize = Resize;
if (resize != null)
{
resize(this, EventArgs.Empty)
}
It should be noted that the above code will call the subscribers to the event, but will not cause the cotrol to resize. If what you want is to change the size of your control, then do that:
this.Size = new Size(400, 200);
Or:
this.Width = 400;
this.Height = 200;
Note: I don't know what Control class you are using. In particular, if it were System.Windows.Forms.Control it already has a Resize event, and thus you won't be defining your own. Chances are you are using a Control class that doesn't even have Size or Width and Height.
Edit: System.Web.UI.Control doesn't have Resize, nor Size or Width and Height. But System.Windows.Controls.Control has Width and Height even thought it doesn't have Resize.
I needed functionality that doesn't exist in the standard ComboBox, so I wrote my own from a TextBox and a form. When the user types in the TextBox, it shows a dropdown as a separate form.
Here's some of the relevant code:
internal class FilteredDropDown : Form
{
public Control OwnerControl { get; set; }
public bool CloseOnLostFocus { get; set; }
protected override OnLostFocus(EventArgs e)
{
if (CloseOnLostFocus && !OwnerControl.IsFocused)
this.Close();
}
protected override OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e)
// highlight the moused over item in the list
}
...
}
public class FilteredCombo : TextBox
{
private FilteredDropDown dropDown;
public FilteredCombo()
{
dropDown = new FilteredDropDown();
dropDown.OwnerControl = this;
}
public void ShowDropDown()
{
if (dropDown.Visible)
return;
dropDown.RefreshFilter();
var loc = PointToScreen(new Point(0, this.Height));
dropDown.Location = loc;
dropDown.CloseOnLostFocus = false;
int selectionStart = this.SelectionStart;
int selectionLength = this.SelectionLength;
dropDown.Show(this);
this.Focus();
this.SelectionStart = selectionStart;
this.SelectionLength = selectionLength;
dropDown.CloseOnLostFocus = false;
}
protected override OnLostFocus(EventArgs e)
{
if (dropDown.Visible && !dropDown.ContainsFocus())
dropDown.Close();
}
protected override OnTextChanged(EventArgs e)
{
base.OnTextChanged(e);
ShowDropDown();
}
...
}
There's obviously a whole lot more code than that to deal with all kinds of stuff irrelevent to my question.
The problem is when I put the FilteredCombo on a modal dialog. Somehow the FilteredDropDown form doesn't receive mouse events at all when it is parented by a modal dialog.
I've read something about WinForms filtering out events on all except the current modal dialog, I suspect that is what's going on, but I have no ideas of how to fix it. Is there some way to get the mouse up/down/move/click/etc. events to work when parented by a model dialog?
I had to go digging through the ShowDialog source code, and I found that it calls user32.dll EnableWindow(Handle, false) on all the windows except the shown one. The problem was that the FilteredDropDown already existed by the time the ShowDialog() method got called. I discovered two different ways to fix this:
Don't allow the DropDown to be shown until the parent form is shown. This is a bit trickier to guarantee, so I also implemented the second way.
Re-enable the DropDown window when it is made visible:
[DllImport("user32.dll")]
private static extern bool EnableWindow(IntPtr hWnd, bool enable);
protected override void OnVisibleChanged(EventArg e)
{
base.OnVisibleChanged(e);
if (this.Visible)
{
EnableWindow(this.Handle, true);
}
}
I would just simply like to be able to minimize the application bar when I am scrolling down, and then show its normal size when scrolling up. I've seen this ability on the facebook app and it seems very appealing and user friendly. I have my LongListSelector with items bound to it, and an appbar already in code behind. What is the missing key to enable such a feature?
You just need to figure out when the user is scrolling and in what direction. Here's a great article with example code. Detecting WP8 LongListSelector’s end of scroll. You can modify it to the point where it does exactly what you want.
However, if I was going do it, I would take a more direct route. I would derived my own LLS and attach a property to the value of the scrollbar. Something like this :)
public class MyLLS : LongListSelector, INotifyPropertyChanged
{
// implement the INotify
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
// dat grab doe
sb = this.GetTemplateChild("VerticalScrollBar") as System.Windows.Controls.Primitives.ScrollBar;
sb.ValueChanged += sb_ValueChanged;
}
void sb_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
// an animation has happen and they have moved a significance distance
// set the new value
ScrollValue = e.NewValue;
// determine scroll direction
if(e.NewValue > e.OldValue)
{
scroll_direction_down = true;
}
else
{
scroll_direction_down = false;
}
}
public System.Windows.Controls.Primitives.ScrollBar sb;
private bool scroll_direction_down = false; // or whatever default you want
public bool ScrollDirectionDown
{ get { return scroll_direction_down; } }
public double ScrollValue
{
get
{
if (sb != null)
{
return sb.Value;
}
else
return 0;
}
set
{
sb.Value = value;
NotifyPropertyChanged("ScrollValue");
}
}
}
Now you know the exact scroll position. You can even get the top and bottom value by doing
double min = this.sb.Minimum;
double max = this.sb.Maximum;
Now bind that ScrollDirectionDown property to a converter to your AppBar visibility and you'll have your goals met.
If you can't bind then you have to do a callback to update the visibility. But if you want something more simple just hook it up to the ManipulationStateChanged event of the custom LLS.
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
}
private void lls_ManipulationStateChanged(object sender, EventArgs e)
{
if (lls.ScrollDirectionDown)
{
ApplicationBar.IsVisible = false;
}
else
{
ApplicationBar.IsVisible = true;
}
}
}
So for that you have to detect when the longlistselector starts scrolling. For that to achieve there's a similar thread here:
Windows Phone 8 Long List Selector - scroll to bottom after data loaded async
In the DoAndScroll method you could simply include the code to minimize the AppBar.
Within your xaml code of your appbar, change the mode to Minimized.
<shell:ApplicationBar Mode="Minimized" Opacity="1.0" IsMenuEnabled="True" IsVisible="True"></>
Thereafter whenever it scrolls back up, make the Mode of the AppBarto Default.
Or else have a look at this to detect the bottom of the longlistselector.
Detecting WP8 LongListSelector’s end of scroll
Why tooltip, displayed manually with ToolTip.Show, is not shown, when window, containing control, is inactive?
public class MyControl : Button
{
private _tip;
public string ToolTip
{
get { return _tip; }
set { _tip = value; }
}
private ToolTip _toolTip = new ToolTip();
public MyControl()
{
_toolTip.UseAnimation = false;
_toolTip.UseFading = false;
_toolTip.ShowAlways = true;
}
protected override void OnMouseHover(EventArgs e)
{
_toolTip.Show(_tip, this, 0, Height);
base.OnMouseHover(e);
}
protected override void OnMouseLeave(EventArgs e)
{
_toolTip.Hide(this);
base.OnMouseLeave(e);
}
}
I went for ToolTip.Show because I must have tooltip onscreen for unlimited time, which is not possible with normal ToolTip. I also love the idea of having tooltip text as a part of control itself. But unfortunately, when showing tooltip this way for inactive window (despite ShowAlways = true), it simply doesn't work.
The OnMouseHower event is rised, but _toolTip.Show does nothing.. unless window is activated, then everything works.
Bounty
Adding bounty for a solution to display tooltip for an inactive form (preferably with solution when tooltip text is a property of control, not IContainer).
There is a private method that does what you want, so to access it, you would have to use reflection to call it:
using System.Reflection;
public class MyControl : Button {
private ToolTip toolTip = new ToolTip() {
UseAnimation = false,
UseFading = false
};
public string ToolTip { get; set; }
protected override void OnMouseHover(EventArgs e) {
base.OnMouseHover(e);
Point mouse = MousePosition;
mouse.Offset(10, 10);
MethodInfo m = toolTip.GetType().GetMethod("SetTool",
BindingFlags.Instance | BindingFlags.NonPublic);
m.Invoke(toolTip, new object[] { this, this.ToolTip, 2, mouse });
}
protected override void OnMouseLeave(EventArgs e) {
base.OnMouseLeave(e);
toolTip.Hide(this);
}
}
The tip will display on an inactive window and it will stay on the screen indefinitely until the mouse moves off the control.