I am aware that in DataGridview, we can bind a ImageColumn to image data to display icon such as. Normally I would use icons from Microsoft's MsoImage.
It occurs to me that from symbol font, we can have many nice icons. Is it possible to bind the column to text instead, with fonts taken into account, so that we can make use of symbol font and display the result of text + font that looks like icons.
If text binding is not possible, is there another way of extracting/converting the symbol font into images?
All you need is to set the Font for the Column. Here is am example:
List<daz> dazz = new List<daz>() { new daz("♻", "267B"), new daz("⚔", "2694") };
Font f = new Font("Segue UI Symbol", 12f);
dataGridView1.DataSource = dazz;
dataGridView1.Columns[0].DefaultCellStyle.Font = f;
Ignore the example class:
class daz
{
public string code { get; set; }
public string text { get; set; }
public daz (string c, string t) { code = c; text = t; }
}
Related
I want to put a cell in every row I have. If a cell that contains an invoice is open, I want to display a certain picture and if it is closed, I want to display another picture in that cell.
Error picture:
Code:
this.dgvBills.DataSource = bill.SearchBills(txtSearch.Text, coBoxState.Text);
DataGridViewImageColumn img = new DataGridViewImageColumn();
img.Name = "img";
img.HeaderText = "Image Column";
img.ValuesAreIcons = true;
dgvBills.Columns.Add(img);
int number_of_rows = dgvBills.RowCount;
for (int i = 0; i < number_of_rows; i++)
{
if (dgvBills.Rows[i].Cells[11].Value.ToString() == "open")
{
dgvBills.Rows[i].Cells["img"].Value = pbox.Image;
}
else
{
dgvBills.Rows[i].Cells["img"].Value = pbox.InitialImage;
}
There are several approaches to this. For a purely visual indicator like this icon, you may be better off displaying the icon during cell formatting.
Handle the DataGridView's CellFormatting event-
private void dgvBills_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
switch (dgvBills.Columns[e.ColumnIndex].Name)
{
case "img": // The name of your image column
if (dgvBills.Rows[e.RowIndex].Cells[11].Value.ToString() == "open")
e.Value = pbox.Image; // image stored in a PictureBox
else
e.Value = pbox.InitialImage; // image stored in a PictureBox
break;
}
}
You can clean this up further by changing your image source. Ditch the PictureBox, and use your project Resources. As an example, if you created two 16x16 PNG icons to represent open and closed states, you can add them to your project Resources as open_invoice and closed_invoice.
Then the value assignments become more readable in your code-
e.Value = new Bitmap(Properties.Resources.open_invoice);
e.Value = new Bitmap(Properties.Resources.closed_invoice);
Or if you need to set a "blank" icon-
e.Value = new Bitmap(1, 1);
If you have control over your Data Source, you can tidy this even further. Let suppose that your bill.SearchBills() function returns List<Bill>. Then you can design your Bills class to return a Bitmap directly as a class Property.
public class Bill
{
public Image OpenClosedIcon
{
get
{
return IsOpen
? new Bitmap(Properties.Resources.open_invoice)
: new Bitmap(Properties.Resources.closed_invoice);
}
}
public bool IsOpen
{
get;
set;
}
// The rest of your Bill class definition...
}
The advantage of this is data binding. When the data source provides it, the DataGridView can recognize the Bitmap field and render it correctly in a DataGridViewImageColumn, without additional work from you.
The easiest approach is usually to use the DataGridView's built-in column designer, and create the columns you want. For your DataGridViewImageColumn, set the DataPropertyName to your class field name OpenClosedIcon
With a fully-prepared data source, you likely won't need the CellFormatting handler at all.
I am using a group box and there are several controls inside this.
My requirement is to set the group box title to the middle of the group box instead of Left.
How?
you can extend the group box class like this.
public class CustomGrpBox : GroupBox
{
private string _Text = "";
public CustomGrpBox()
{
//set the base text to empty
//base class will draw empty string
//in such way we see only text what we draw
base.Text = "";
}
//create a new property a
[Browsable(true)]
[Category("Appearance")]
[DefaultValue("GroupBoxText")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public new string Text
{
get
{
return _Text;
}
set
{
_Text = value;
this.Invalidate();
}
}
protected override void OnPaint(PaintEventArgs e)
{
//first let the base class to draw the control
base.OnPaint(e);
//create a brush with fore color
SolidBrush colorBrush = new SolidBrush(this.ForeColor);
//create a brush with back color
var backColor = new SolidBrush(this.BackColor);
//measure the text size
var size = TextRenderer.MeasureText(this.Text, this.Font);
// evaluate the postiong of text from left;
int left = (this.Width - size.Width) / 2;
//draw a fill rectangle in order to remove the border
e.Graphics.FillRectangle(backColor, new Rectangle(left, 0, size.Width, size.Height));
//draw the text Now
e.Graphics.DrawString(this.Text, this.Font, colorBrush, new PointF(left, 0));
}
}
add the above class into your project and use "CustomGrpBox" instead of "GroupBox" which will be created after build in your tool box.
and you can set the text any time like this.
private void Form2_Load(object sender, EventArgs e)
{
customGrpBox1.Text = "Hello World";
}
it will look like this in design time visual studio
Unfortunately, you may set the title on the right by using the RightToLeft property, but there is no property to set it in the middle.
What you can do is to set an empty Text in your GroupBox, create a Label with the title and put that label above the GroupBox (with the same parent).
You may do it dynamically at form initialization by calling following procedure:
private void CenterGroupBoxTitle(GroupBox groupbox)
{
Label label = new Label() ;
label.Text = groupbox.Text ;
groupbox.Text = "" ;
label.Left = groupbox.Left+(groupbox.Width-label.Width)/2 ;
label.Top = groupbox.Top + 2 ; // 2 is an example : adjust the constant
label.Parent = groupbox.Parent ;
label.BringToFront() ;
}
Try to create a custom control using Panel as container and draw border around this, you can then have full control of the title's alignment.
If you would like a simple approach, you can leave the groupbox's title as empty text, and then place a label at the center position of the groupbox. You can also define this as user-control so you wouldn't need to do this repeatedly.
Not an eloquent solution, but if you have a simple GroupBox, that stays the( same size, you can just pad the beginning, and the end with spaces.
example : GroupBox.Text = " This is the groupbox text ";
The amount of padding of space's will depend on the length of the box.
Of course you'll lose some of the GroupBox's beginning and end lines on top, and if that's important, then Answer 3 seems like a good solution.
So, I know there are multiple thread on how to do the conversion between the aforementioned systems. And I know they're not 1-to-1. However, I'm hoping there's a way to be able to get things to work.
The fonts specifically in question are just examples, as I'm sure others have the same issue, Segoe UI just happens to be my default font. What's not working though, is when I select Segoe UI Semibold Italic or some other in-between font.
Here's my conversion code:
// Font family
FontFamilyConverter ffc = new FontFamilyConverter();
TextContent.FontFamily = (System.Windows.Media.FontFamily)
ffc.ConvertFromString(fontDialog.Font.Name);
// Font size
TextContent.FontSize = fontDialog.Font.Size;
// Bold?
TextContent.FontWeight = (fontDialog.Font.Bold ? FontWeights.Bold : FontWeights.Normal);
// Italic?
TextContent.FontStyle = (fontDialog.Font.Italic ? FontStyles.Italic : FontStyles.Normal);
// Underline and strikethrough?
TextContent.TextDecorations = new TextDecorationCollection();
if (fontDialog.Font.Strikeout) {
TextContent.TextDecorations.Add(TextDecorations.Strikethrough);
}
if (fontDialog.Font.Underline) {
TextContent.TextDecorations.Add(TextDecorations.Underline);
}
// Color
TextContent.Foreground = new SolidColorBrush(
System.Windows.Media.Color.FromArgb(fontDialog.Color.A,
fontDialog.Color.R,
fontDialog.Color.G,
fontDialog.Color.B)
);
From using the debugger, I know that the Italic property is being properly set, but the font isn't coming through as Semibold Italic it's just coming through as Semibold. If (when in the debugger) I change the FontFamily to "Segoe UI Semibold Italic" then it works.
Is there something I'm missing to be able to get all the styles to come across correctly?
Thanks.
Note: I know size isn't working correctly. Just haven't fixed it yet
Here is what I ended up with:
After the dialog returns OK:
FontFamilyConverter ffc = new FontFamilyConverter();
TextContent.FontFamily = (System.Windows.Media.FontFamily) ffc.ConvertFromString(getFontName(fontDialog.Font));
A helper method:
private List<string> limitFontList(List<string> fontList, string word) {
// Create a new list
var newFontList = new List<string>();
// Go through each element in the list
foreach (var fontFamily in fontList) {
// If the elment contains the word
if (fontFamily.ToLower().Contains(word.ToLower())) {
// Add it to the new list
newFontList.Add(fontFamily);
}
}
// Return the new list if anything was put in it, otherwise the original list.
return newFontList.Count > 0 ? newFontList : fontList;
}
getFontName:
private string getFontName(Font font) {
// Holds the font we want to return. This will be the original name if
// a better one cannot be found
string fontWanted = font.FontFamily.Name;
// Create a new Media.FontFamily
var family = new System.Windows.Media.FontFamily(fontWanted);
/// Get the base font name
string baseFont = ""; // Holds the name
/* FamilyNames.Values will holds the base name, but it's in a collection
** and the easiest way to get it is to use a foreach. To the best of my
** knowledge, there is only ever one value in Values.
** E.g. If the font set is Segoe UI SemiBold Italc, gets Segoe UI.
*/
foreach(var baseF in family.FamilyNames.Values){
baseFont = baseF;
}
// If the baseFont is what we were passed in, then just return
if(baseFont == fontWanted) {
return fontWanted;
}
// Get the typeface by extracting the basefont from the name.
// Trim removes any preceeeding spaces.
string fontTypeface = fontWanted.Substring(baseFont.Length).Trim();
// Will hold all of the font names to be checked.
var fontNames = new List<string>();
// Go through all of the available typefaces, and add them to the list
foreach (var typeface in family.FamilyTypefaces) {
foreach(var fn in typeface.AdjustedFaceNames) {
fontNames.Add(baseFont + " " + fn.Value);
}
}
// Limit the list to elements which contain the specified typeface
fontNames = limitFontList(fontNames, fontTypeface);
// If the font is bold, and the original name doesn't have bold in it (semibold?)
if(!baseFont.ToLower().Contains("bold") && font.Bold) {
fontNames = limitFontList(fontNames, "bold");
}
// In a similar manner for italics
if (!baseFont.ToLower().Contains("italic") && font.Italic) {
fontNames = limitFontList(fontNames, "italic");
}
// If we have only one result left
if(fontNames.Count == 1) {
return fontNames[0];
}
// Otherwise, we can't accurately determine what the long name is,
// So hope whatever the short name is will work.
return fontWanted;
}
I have a Panel filled with a lot of controls for users to fill. These include textboxes, checkboxes, radiobuttons etc. It is a long form to fill so the controls are in a scrollable panel. What I need is to save the whole panel as pdf. I think PDFsharp is a good library to be able to save any text or image as a pdf file but I don't want to write code for every single control inside the panel. I once wrote a class to create a pdf file from a Control object. It was iterating all inner controls (and their inner controls until no inner control is left) of the given control and write their Text property (yes/no for chekable controls) to pdf using their Location and Size properties. I could not find it now but I remember it was having issues with some of the DevExpress controls I use so I didn't bother writing it again. (Edit: I had to, you can find it below.) I think taking a screenshot and save that image as pdf would be nice but I couldn't find out how to achieve it. This question seems like it but there is no satisfying answer to that.
So, screenshot or not I'm open for any advice. There should be many occasions where users must fill long forms and be able to keep it as pdf. Again, any advice or workaround would be appreciated. (I think about creating the form using html, displaying it in a WebBrowser control and using an html to pdf library but I really prefer using my existent form)
Many Thanks.
Edit:
I had to write something iterates inner controls of a container control (like a panel) and writes every inner control to a pdf using their Location, Size and Font properties though, I don't recommend to use it (at least as it is) because of these:
It sets the page's size to given control's size and use only one (usually huge) pdf page. You can add a logic to split it to pages if you need to. (I didn't, but I guess you'll probably need your pdf more printer friendly).
Cheeso's method (using a FlowDocument) is a much more "legitimate" way for a task like this. I prefer using that over this but I didn't have a choice in this instance.
I used PDFsharp in this code. You can find it in it's hompage or it's CodePlex page.
PdfReport class:
private PdfDocument Document;
public Control Control { get; private set; }
public PdfReport(Control control) { Control = control; }
public PdfDocument CreatePdf(PdfDocument document = null)
{
Document = document != null ? document : new PdfDocument();
PdfPage page = Document.AddPage();
page.Height = Control.Height;
page.Width = Control.Width;
XGraphics gfx = XGraphics.FromPdfPage(page);
foreach (PdfItem item in CreatePdf(new Point(0, 0), Control.Controls))
{
XStringFormat format = item.IsContainer ? XStringFormats.TopLeft : item.TextAlign == ContentAlignment.BottomCenter ? XStringFormats.BottomCenter : item.TextAlign == ContentAlignment.TopLeft ? XStringFormats.TopLeft : item.TextAlign == ContentAlignment.TopCenter ? XStringFormats.TopCenter : XStringFormats.Center;
gfx.DrawString(item.Text, item.Font, item.Brush, new XRect(item.Location, item.Size), format);
}
return Document;
}
private IEnumerable<PdfItem> CreatePdf(Point location, Control.ControlCollection controls)
{
List<PdfItem> items = new List<PdfItem>();
foreach (Control control in controls)
{
if (control.Controls.Count > 0)
items.AddRange(CreatePdf(control.Location, control.Controls));
items.Add(new PdfItem(control, location));
}
return items;
}
public void SaveAsPdf(string path, bool open = false)
{
CreatePdf().Save(path);
if (open)
Process.Start(path);
}
PdfItem class:
public string Text { get; set; }
public Point Location { get; set; }
public Size Size { get; set; }
public Font Font { get; set; }
public bool IsContainer { get; set; }
public ContentAlignment TextAlign { get; set; }
public Color ForeColor { get; set; }
public XBrush Brush { get { return new SolidBrush(ForeColor); } }
public PdfItem() { }
public PdfItem(string text, Point location, Font font, Color foreColor, Size size, bool isContainer = false, ContentAlignment alignment = ContentAlignment.MiddleCenter)
{
Text = text;
Location = location;
Size = size;
Font = new Font(font.FontFamily, font.Size, font.Style, GraphicsUnit.World);
TextAlign = alignment;
ForeColor = foreColor;
IsContainer = isContainer;
}
public PdfItem(string text, Point location, Size size)
: this(text, location, new Font("Calibri", 12), Color.Black, size) { }
public PdfItem(Control control, Point parentLocation)
: this(control.Text, control.Location, control.Font, control.ForeColor, control.Size, control.Controls.Count > 0)
{
Location = new Point(Location.X + parentLocation.X, Location.Y + parentLocation.Y);
IEnumerable<PropertyInfo> properties = control.GetType().GetProperties();
if (properties.FirstOrDefault(p => p.Name == "TextAlign" && p.PropertyType == typeof(ContentAlignment)) != null)
TextAlign = (control as dynamic).TextAlign;
if (properties.FirstOrDefault(p => p.Name == "Checked" && p.PropertyType == typeof(bool)) != null)
{
string title = control.Text != null && control.Text.Length > 0 ? string.Format("{0}: ", control.Text) : string.Empty;
Text = string.Format("{0}{1}", title, (control as dynamic).Checked ? "Yes" : "No");
}
}
Regarding
. I think taking a screenshot and save that image as pdf would be nice but I couldn't find out how to achieve it.
There is a tool called "cropper" available on codeplex.com. It is designed to be used as a user tool that can take screenshots. It is managed code, open source.
I can imagine embedding some of the cropper magic into your app so that you could take that screenshot. I can also imagine this would be useful for collecting a diagnostic image of the screen at the time of a problem.
On the other hand... if you are interested in producing a printed form that reproduces the content on the screen, then I think you should be using WPF, in which case doing what you want is pretty easy. For example, this question describes how to do a print-preview for a FlowDocument. From that point your user can print to PDF (if he has a PDF printer installed) or print to XPS, or print to a physical output device, and so on.
I don't know if this would help you or not, but DocRaptor.com's pdf api could be built in so it would do it for you, no matter what the user inputs. It uses basic html.
As you can use the below :)
YourPanel.AutoSize = true;
int width = YourPanel.Size.Width;
int height = YourPanel.Size.Height;
Bitmap bm = new Bitmap(width, height);
YourPanel.DrawToBitmap(bm, new Rectangle(0, 0, width, height));
string outputFileName = #"C:\YourDirectory/myimage.bmp";
using (MemoryStream memory = new MemoryStream())
{
using (FileStream fs = new FileStream(outputFileName, FileMode.Create, FileAccess.ReadWrite))
{
bm.Save(memory, ImageFormat.Bmp);
Clipboard.SetImage(bm);
byte[] bytes = memory.ToArray();
fs.Write(bytes, 0, bytes.Length);
}
}
YourPanel.AutoSize = false;
The Clipboard.SetImage will send you bm to the clipboard so you can paste them to your pdf form or whatever document
This also has an example built in that saves it as a image for you if you want.
The trick here is Autosize for your panel. It needs to be set to true so the panel resizes itself as a whole area visible, then right after you do your work you can resize it to false so it uses scrollbars again for the users screen (you may see it flash for half a second, but this code does work.
Saving it in a PDF I personally just prefer to write it there as my clipboard or you can write byte. But ITextSharp is a great library for the extension to work with!
I Really hope this helps.
I need some code to convert standard C# TextBox to temperature TextBox which means adding "°C" to end of the text in the textbox with another color than the default color.
To get the degree symbol you can use character code 176 e.g.
Char degree = (Char)176
You can then append this to your textbox content or I would just add a label to the right of the textbox with the degree symbol if you want to control the forecolor easily.
TextBox is a plain text editor. To get different colours you would have to muck around with a rich text box. Why not put the "°C" in a label positioned to the right of the text box? That would also make your parsing and rendering code much easier.
You could probably create your own control which inherits from TextBox and then override Text property to automaticaly add °C though other color inside the same TextBox could be problem.
Why you want to have °C in TextBox ?
Can't it just be label right after TextBox ?
You can set static text and color to what you want.
The other solutions proposed here are probably sufficient for your application; however, if you had the need to implement this with re-usability in mind, here is a custom control solution which you may extend to better suit your application:
public class TemperatureTextBox : ContainerControl
{
private const int BORDER_SIZE = 1;
// Exposes text property of text box,
// expose other text box properties as needed:
public override string Text
{
get { return textBox.Text; }
set { textBox.Text = value; }
}
private TextBox textBox = new TextBox()
{
Text = string.Empty,
BorderStyle = BorderStyle.None,
Dock = DockStyle.Fill
};
private Label label = new Label()
{
Text = "°C",
TextAlign = ContentAlignment.MiddleCenter,
Size = new Size()
{
Width = 32
},
BackColor = SystemColors.Window,
Dock = DockStyle.Right
};
public TemperatureTextBox()
{
this.BackColor = SystemColors.Window;
this.Padding = new Padding(BORDER_SIZE);
this.Controls.Add(label);
this.Controls.Add(textBox);
this.PerformLayout();
}
// Constrain control size to textbox height plus top and bottom border:
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
this.Height = (textBox.Height + (BORDER_SIZE * 2));
}
// Render a border around the control:
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.DrawRectangle(
SystemPens.ControlDarkDark,
new Rectangle()
{
Width = (this.Width - BORDER_SIZE),
Height = (this.Height - BORDER_SIZE)
});
}
}
Simply create a new class and drop this code in and rebuild you solution. It will create a new TemperatureTextBox control in the toolbox which can be dropped onto a new form and visually designed.
This example exposes the Text property of the underlying text box by overriding the custom control's text property. You may want to expose other properties, and events depending on what your application needs to accomplish.