Morning all,
I've created a custom control with an image property. That image property is a get/set to a private Image variable.
Can anyone tell me how I enable that get/set to clear the property from the designer?
I.e. if I add an image to a standard PictureBox, I can hit Del to clear the image from the PictureBox. How can I replicate this behaviour on my own custom control?
At the simplest level, DefaultValueAttribute should do the job:
private Bitmap bmp;
[DefaultValue(null)]
public Bitmap Bar {
get { return bmp; }
set { bmp = value; }
}
For more complex scenarios, you might want to try adding a Reset method; for example:
using System;
using System.Drawing;
using System.Windows.Forms;
class Foo {
private Bitmap bmp;
public Bitmap Bar {
get { return bmp; }
set { bmp = value; }
}
private void ResetBar() { bmp = null; }
private bool ShouldSerializeBar() { return bmp != null; }
}
static class Program {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Form form = new Form();
PropertyGrid grid = new PropertyGrid();
grid.Dock = DockStyle.Fill;
grid.SelectedObject = new Foo();
form.Controls.Add(grid);
Application.Run(form);
}
}
Related
I just wrote thsi code to have an access to images
private Bitmap[] hi = { HangmanUrdu.Properties.Resources._4, HangmanUrdu.Properties.Resources._5, HangmanUrdu.Properties.Resources._6, HangmanUrdu.Properties.Resources._7, HangmanUrdu.Properties.Resources._8, HangmanUrdu.Properties.Resources._9, HangmanUrdu.Properties.Resources._10 };
but when i want to increment the index and get these images in my picture box
// wg is just a counter;
pictureBox1.Image = hi { wg}; i
t throws me an error saying
cannot implicitly convert Bitmap to images
I also tried to change my array from bitmap to image but then it shows me error that cannot convert Images to Images.
Create a List<Bitmap> - as a Field, here - or any other type that fits the design (a class property, for example).
Fill the List<Bitmap> in a Form's constructor with the Bitmap objects needed in that context, creating a new Bitmap from the resource object:
private List<Bitmap> hi = null;
public Form1()
{
InitializeComponent();
this.hi = new List<Bitmap>()
{
new Bitmap(Properties.Resources._4),
new Bitmap(Properties.Resources._5)
};
}
The assign a Bitmap to a control's Image property when you need to:
pictureBox1.Image = hi[1];
You could also build a specialized class that hold these references, so you can access them with different naming conventions.
For example:
private List<BitmapResource> BitmapResources = null;
public Form1()
{
InitializeComponent();
this.BitmapResources = new List<BitmapResource>()
{
new BitmapResource(new Bitmap(Properties.Resources._4), "Logo"),
new BitmapResource(new Bitmap(Properties.Resources._5), "Watermark")
};
}
internal class BitmapResource
{
public BitmapResource(Bitmap bitmap, string imageName)
{
this.Image = bitmap;
this.Name = imageName;
}
public Bitmap Image { get; private set; }
public string Name { get; private set; }
}
Then, when needed:
By index:
pictureBox1.Image = BitmapResources[0].Image;
By name (simplified):
pictureBox1.Image = BitmapResources.FirstOrDefault(res => res.Name == "Logo").Image;
I have a ToolStripSplitButton with various elements in dropdown list.
One of them is a Trackbar enclosed in a ToolStripControlHost, called ToolStripTrackbarItem. It's code (I've got it from stackoverflow):
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.Design;
namespace Application
{
[System.ComponentModel.DesignerCategory("code")]
[System.Windows.Forms.Design.ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.ContextMenuStrip | ToolStripItemDesignerAvailability.MenuStrip)]
public class ToolStripTrackbarItem : ToolStripControlHost
{
public ToolStripTrackbarItem()
: base(CreateControlInstance())
{
this.Size = Control.Size;
}
public TrackBar TrackBar
{
get { return Control as TrackBar; }
}
private static Control CreateControlInstance()
{
TrackBar t = new TrackBar();
t.AutoSize = false;
return t;
}
[DefaultValue(0)]
public int Value
{
get { return TrackBar.Value; }
set { TrackBar.Value = value; }
}
protected override void OnSubscribeControlEvents(Control control)
{
base.OnSubscribeControlEvents(control);
TrackBar trackBar = control as TrackBar;
trackBar.ValueChanged += new EventHandler(trackBar_ValueChanged);
}
protected override void OnUnsubscribeControlEvents(Control control)
{
base.OnUnsubscribeControlEvents(control);
TrackBar trackBar = control as TrackBar;
trackBar.ValueChanged -= new EventHandler(trackBar_ValueChanged);
}
void trackBar_ValueChanged(object sender, EventArgs e)
{
if (this.ValueChanged != null)
ValueChanged(sender, e);
}
public event EventHandler ValueChanged;
protected override Size DefaultSize
{
get { return new Size(300, 16); }
}
}
It works, but I need to show images to the left of the dropdown items:
I'm successful with a simple ToolStripMenuItem by setting the Image property. However, it is ineffective to set Image property of my ToolStripTrackbarItem (that is inherited from ToolStripControlHost, see code above). According to MSDN, Image property is irrelevant to ToolStripControlHost.
What does it mean? Is it not even possible to include an image left to ToolStripControlHost?
If it is possible anyway, how to do that?
You should solve 2 problems here:
ToolStripControlHost doesn't show Image property and also doesn't serialize the image when you save the form.
ToolStripProfessionalRendered doesn't draw image for ToolStripControlHost.
You need to override Image property of ToolStripControlHost and make it browsable and serializable. Also you need to create a custom renderer to draw the image in the correct location and size. Then if you simply set the renderer for ToolStrip using below code, you will get expected result:
this.toolStrip1.Renderer = new MyCustomRenderer();
ToolStripTrackBar
The item enables Image property to show in property grid and let it serialize when saving form.
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Forms.Design;
[ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.All)]
public class ToolStripTrackBar : ToolStripControlHost
{
public TrackBar TrackBar { get { return (TrackBar)Control; } }
public ToolStripTrackBar() : base(CreateControl()) { }
private static TrackBar CreateControl()
{
var t = new TrackBar()
{ TickStyle = TickStyle.None, AutoSize = false, Height = 28 };
return t;
}
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public override Image Image
{
get { return base.Image; }
set { base.Image = value; }
}
/*Expose properties and events which you need.*/
public int Value
{
get { return TrackBar.Value; }
set { TrackBar.Value = value; }
}
}
MyCustomRenderer
This renderer draws images for ToolStripTrackBar.
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
public class MyCustomRenderer : ToolStripProfessionalRenderer
{
protected override void OnRenderImageMargin(ToolStripRenderEventArgs e)
{
base.OnRenderImageMargin(e);
e.ToolStrip.Items.OfType<ToolStripTrackBar>()
.ToList().ForEach(item =>
{
if (item.Image != null)
{
var size = item.GetCurrentParent().ImageScalingSize;
var location = item.Bounds.Location;
location = new Point(5, location.Y + 1);
var imageRectangle = new Rectangle(location, size);
e.Graphics.DrawImage(item.Image, imageRectangle,
new Rectangle(Point.Empty, item.Image.Size),
GraphicsUnit.Pixel);
}
});
}
}
Question: I have a Winform C# project that changes the tool tip text of a user control tool tip when passed from a host project. I need to pass font size as a variable, but dont know where to make the changes. I have tried a plethora of solutions online and am stuck with this implementation. Any help in this direction will be really appreciated.
What I have so far:
I have a C# user Control project where i have set a property to set the tool tip text to change to user specified value in my UC_ToolTipButton project, where the contents of the project are as below:
UC_ToolTipButton.cs
using System.Windows.Forms;
namespace UC_ToolTipButton
{
public partial class UC_ToolTipButton : UserControl
{
public string TT_Message
{
get{
return ToolTip_Message.GetToolTip(btnTT);
}
set{
ToolTip_Message.SetToolTip(btnTT, value);
}
}
public UC_ToolTipButton()
{
InitializeComponent();
}
}
}
In my designer file, I have placed a button (btnTT) on which I have put a tool tip (ToolTip_Message).
When I compile this User Control Forms project, it works fine and creates a dll file.
Upon importing this file in a project TryButtonTooltip, where I have the file TryTooltipForm.cs with the following content
using System.Windows.Forms;
namespace TryButtonToolTip
{
public partial class TryToolTipForm : Form
{
public TryToolTipForm()
{
InitializeComponent();
uC_TTMessage.TT_Message = #"Hi";
}
}
}
Set OwnerDraw on ToolTip to true, in ToolTip's Draw event set the desired font, then in Popup event measure and set the size of your ToolTip, as is explained in the example here.
For example like this (untested):
public partial class UC_ToolTipButton : UserControl
{
public string TT_FontFamily { get; set; }
public float TT_FontSize { get; set; }
public string TT_Message
{
get
{
return ToolTip_Message.GetToolTip(btnTT);
}
set
{
ToolTip_Message.SetToolTip(btnTT, value);
}
}
public UC_ToolTipButton()
{
InitializeComponent();
TT_FontFamily = "Tahoma";
TT_FontSize = 10;
ToolTip_Message.OwnerDraw = true;
ToolTip_Message.Draw += new DrawToolTipEventHandler(TT_Draw);
ToolTip_Message.Popup += new PopupEventHandler(TT_Popup);
}
private void TT_Popup(object sender, PopupEventArgs e)
{
using (Font f = new Font(TT_FontFamily, TT_FontSize))
{
e.ToolTipSize = TextRenderer.MeasureText(ToolTip_Message.GetToolTip(e.AssociatedControl), f);
}
}
private void TT_Draw(System.Object sender,
System.Windows.Forms.DrawToolTipEventArgs e)
{
e.DrawBackground();
e.DrawBorder();
using (StringFormat sf = new StringFormat())
{
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
using (Font f = new Font(TT_FontFamily, TT_FontSize))
{
e.Graphics.DrawString(e.ToolTipText, f, SystemBrushes.ActiveCaptionText, e.Bounds, sf);
}
}
}
}
My main goal is to load an image from a server and while the loading process is running I would like to show a placeholder instead of the real image.
For reaching this goal I am using C# and Windows Forms. I have to use the proxy pattern and C# background worker which means the loading and the view are using different threads.
I know there are already examples of using proxy pattern for image loading but I have not found any solution which uses a background worker for loading images from a server.
I have already implemented the core functionality but I am now stucking at the question: When the image is fully loaded and therefore the background worker has done his job, how can I force my picture box to load the real image.
My design looks like this:
public class MyPictureBox : PictureBox
{
AbstractImage myImage;
public MyPictureBox(AbstractImage image) : base()
{
this.myImage = image;
}
}
public abstract class AbstractImage
{
protected readonly String url;
public AbstractImage(String url)
{
this.url = url;
}
public abstract Image getImage();
}
public class RealImage : AbstractImage
{
private Image img;
public RealImage(String url) : base(url)
{
}
public override Image getImage()
{
if (img == null)
{
WebRequest requestPic = WebRequest.Create(url);
WebResponse responsePic = requestPic.GetResponse();
img = Image.FromStream(responsePic.GetResponseStream());
}
return img;
}
}
public class ProxyImage : AbstractImage
{
private readonly Image Dummy = Image.FromFile("Waiting.jpg");
private readonly RealImage realImage;
public readonly BackgroundWorker bgw;
private bool done = false;
public ProxyImage(String url) : base(url)
{
realImage = new RealImage(url);
bgw = new BackgroundWorker();
bgw.WorkerReportsProgress = true;
bgw.DoWork += new DoWorkEventHandler(loadImage);
bgw.RunWorkerAsync();
}
public void loadImage(object sender, DoWorkEventArgs e)
{
Console.WriteLine("Loading file" + url);
realImage.getImage();
Console.WriteLine("Finished loading file " + url);
done = true;
bgw.ReportProgress(100);
}
public override Image getImage()
{
return done ? realImage.getImage() : Dummy;
}
}
public partial class Form1 : Form
{
private String urlPrefix = "http://...";
String[] filenames = { "Penguins.jpg", "Koala.jpg", "Desert.jpg"};
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Form1_Shown(object sender, EventArgs e)
{
ProxyImage image = new ProxyImage(urlPrefix + filenames[0]);
MyPictureBox pb = new MyPictureBox(image);
pb.Image = image.getImage();
pb.SizeMode = PictureBoxSizeMode.Zoom;
pb.Size = new Size(200, 200);
pb.Location = new Point(0, 0);
Controls.Add(pb);
}
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
At the moment the picture box only shows the dummy image because the background worker has loaded the image but doesn't inform the picture box to use this instead of the dummy image.
I would be glad if anyone could tell my how to set the real image as image of the picture box.
I set a PropertyGrid's SelectedObject to an object with a Bitmap property:
public class Obj
{
private Bitmap myimage;
[Category("Main Category")]
[Description("Your favorite image")]
public Bitmap MyImage
{
get { return myimage; }
set
{
myimage = value;
}
}
}
This automatically shows the property in the PropertyGrid with a little button that the user can click on to select the image. How can I get the file path of this image?
(Also, is there any way I can override the dialog box that pops up and put my own one in? I know this is a separate question so I'll probably post it separately.)
How can I get the file path of this image?
Also, is there any way I can override the dialog box that pops up and put my own one in?
To achieve the both one way would be to create a new UITypeEditor:
public class BitmapLocationEditor : UITypeEditor
{
}
I overrided the GetEditStyle, EditValue, GetPaintvalueSupported and PaintValue methods.
// Displays an ellipsis (...) button to start a modal dialog box
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.Modal;
}
// Edits the value of the specified object using the editor style indicated by the GetEditStyle method.
public override object EditValue(ITypeDescriptorContext context,
IServiceProvider provider,
object value)
{
// Show the dialog we use to open the file.
// You could use a custom one at this point to provide the file path and the image.
using (OpenFileDialog openFileDialog = new OpenFileDialog())
{
openFileDialog.Filter = "Image files (*.bmp | *.bmp;";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
Bitmap bitmap = new Bitmap(openFileDialog.FileName);
bitmap.SetPath(openFileDialog.FileName);
return bitmap;
}
}
return value;
}
// Indicates whether the specified context supports painting
// a representation of an object's value within the specified context.
public override bool GetPaintValueSupported(ITypeDescriptorContext context)
{
return true;
}
// Paints a representation of the value of an object using the specified PaintValueEventArgs.
public override void PaintValue(PaintValueEventArgs e)
{
if (e.Value != null)
{
// Get image
Bitmap bmp = (Bitmap)e.Value;
// This rectangle indicates the area of the Properties window to draw a representation of the value within.
Rectangle destRect = e.Bounds;
// Optional to set the default transparent color transparent for this image.
bmp.MakeTransparent();
// Draw image
e.Graphics.DrawImage(bmp, destRect);
}
}
Your Obj class should remain the same, except add an attribute to take advantage of our new BitmapLocationEditor class:
public class Obj
{
private Bitmap myImage;
[Category("Main Category")]
[Description("Your favorite image")]
[Editor(typeof(BitmapLocationEditor), typeof(UITypeEditor))]
public Bitmap MyImage
{
get { return myImage; }
set
{
myImage = value;
}
}
}
The SetPath method used in EditValue method is just an extension method to set the Bitmap.Tag property. You can use later the GetPath method to retrieve the actual path of your image file.
public static class BitmapExtension
{
public static void SetPath(this Bitmap bitmap, string path)
{
bitmap.Tag = path;
}
public static string GetPath(this Bitmap bitmap)
{
return bitmap.Tag as string;
}
}
Article about PropertyGrid