I want to create a simple 3D line in a WinForms application to improve visual arrangement of my form layout.
This line is exacly like the line in About Windows dialog (can be opened in Windows Explorer -> Help -> About Windows).
An example be checked
The last line (3D) is the one I want, not the first one.
How can this be done in C# or Visual Basic (.NET)?
Add a Label control with a 3D border and with no text then set the height to 2.
var separator = new Label();
separator.BorderStyle = BorderStyle.Fixed3D;
separator.Height = 2;
If you use SysInternals' ZoomIt utility, you can see that this is simply two lines. A dark gray one above a white one. Drawing lines is simple enough with Graphics.DrawLine(), you just need to make sure you pick a dark color that work well with the form's BackColor. That isn't always battleship gray if the user selected another theme. Which makes the GroupBox trick fall flat.
This sample code is serviceable:
protected override void OnPaint(PaintEventArgs e) {
Color back = this.BackColor;
Color dark = Color.FromArgb(back.R >> 1, back.G >> 1, back.B >> 1);
int y = button1.Bottom + 20;
using (var pen = new Pen(dark)) {
e.Graphics.DrawLine(pen, 30, y, this.ClientSize.Width - 30, y);
}
e.Graphics.DrawLine(Pens.White, 30, y+1, this.ClientSize.Width - 30, y+1);
}
Note the use of button1 in this code, there to make sure the line is drawn at the right height, even when the form is rescaled. Pick your own control as a reference for the line.
One way is to create a group box with no label and height 0 (or is it 1, don't quite remember) - I know I've used that trick before, even if it feels a bit hacky :-)
I too have used the GroupBox hack and it's got the benefit of styling itself based on the OS border theme.
There is also a Line class in the VB Power Packs control collection. There's a few other goodies in there that we've used too.
Edit: Here's my Seperator class for drawing horizontal line using the method mentioned above.
public class Separator : GroupBox
{
// Methods
protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
{
base.SetBoundsCore(x, y, width, 3, specified);
}
// Properties
[DefaultValue("")]
public override string Text
{
get
{
return string.Empty;
}
set
{
}
}
}
You can get a line separator effect by adding a Label and setting its text as underscores "_"
I wrote a custom control just for this purpose. You can install the control suite from from NuGet:
Install-Package ALMSTWKND -Version 1.0.0
After installation, it will be added to the Toolbox pane.
Related
I use RichTextBox to display small texts which is much sharper without anti-aliasing. Texts in TextBox is not anti-aliased which gives a sharp outline. But texts in RichTextBox is anti-aliased which is blured. So I want to prevent RichTextBox from anti-aliasing the texts.
I think this is only possible if RichTextBox can also render bitmap-text since for small text, if it is rendered without anti-aliasing, the result won't be readable. So the question is indeed can RichTextBox render text in bitmap mode instead of vector mode?
Environment: Windows 10 x64, VS2017
This question's Disable Anti-aliasing on WinForms text rendering answer doesn't affect RichTextBox.
It turns out that RichTextBox can render bitmap font, it depends on the font that you use, if you use a bitmap font, then RitchTextBox will just render bitmap font...
I use NetRtfWriter https://sourceforge.net/projects/netrtfwriter/ to generate RTF text then put it in RichTextBox's Rtf property.
Win forms test code (txtMain is a RichTextBox)
public Form1()
{
InitializeComponent();
var doc = new RtfDocument(PaperSize.A4, PaperOrientation.Portrait, Lcid.English);
string rtf;
for (int i = 1; i < 20; i++)
{
RtfCharFormat fmt;
//basic text use bitmap font "roman"
RtfParagraph par = doc.addParagraph();
par.setText("("+i+") This is paragraph");
par.DefaultCharFormat.FontSize = i;
//search in Windows, there is a "roman.fon" in the system
//which is a bitmap font
par.DefaultCharFormat.Font = doc.createFont("roman");
//this section use vector font
fmt = par.addCharFormat(14, 17);
fmt.FgColor = doc.createColor(new DW.RtfWriter.Color(0, 0, 255)); ;
fmt.FontSize = i+10;
fmt.Font = doc.createFont("Times New Roman");
}
rtf = doc.render();
txtMain.Rtf=rtf;
}
If you don't set font for a Rtf section, then RichEditBox will use sort of default font (perhaps the same as Windows common controls), for this defaulft font, it will render with bitmap for some range of font sizes, and render vector font for other sizes that is too small or too big to get a good result from bitmap font.
NetRtfWriter has a default built'in font setting which prevent the above to happen so first modify the source code of NetRtfWriter:
In RtfBasics.cs:
//delete public static string Font = "Times New Roman";
public static string Font = null;//add
In RtfDocument.cs:
//delete rtf.AppendLine(#"{\f" + i + " " + RtfUtility.unicodeEncode(_fontTable[i].ToString()) + ";}");
if (_fontTable[i]!=null) rtf.AppendLine(#"{\f" + i + " " + RtfUtility.unicodeEncode(_fontTable[i].ToString()) + ";}");//add
In the above Winforms test code, remove the font setting to use the "default font":
//delete par.DefaultCharFormat.Font = doc.createFont("roman");
Windows/.NET will decide which size will be rendered with bitmap text, so the final result may depends on system configuration. But whatever the configuration is, you can find (with your face very near the screen and use native resolution of the monitor...) some lines of the result rendered with bitmap (if not, expand the range of i).
For my system which is 4K resolution, 300% system enlarge setting, the default Winforms exe will render 9-13 with bitmap. But when enable "High DPI scaling behavior" and set it to "application" for the executable in Explorer, it will only render 3 and 4 with bitmap.
I'm trying to create a graphics library with graphics control. The control enables adding overlay controls. The graphics on the control uses DirectX and is part of the library, while the overlay controls are provided by end users of the library which are not graphics experts. Thus stability and convenient API are the most important issues.
For technical reasons I need to show the graphics by DirectX directly on the control and cannot host the DirectX scene using another framework as WPF (For more information see my previous question: Stereoscopic 3D on WPF).
I think the most problematic issues are:
Transparency (and semi-transparency...) within the area of the control itself.
Animations on the overlay control: That's why control rasterization (e.g. by WPF) is not an option.
My tries until now:
Following the lot of posts discussed similar issues I decided to use WS_EX_TRANSPARENT. I was surprised to see that although the Airspace issue, I can see the DirectX content under the transparent regions of the overlay control. However the overlay control was not shown except for when I resized the window - then it blinks and disappears again. Here is the code of the overlay control:
class GDIGraphicsControl : UserControl
{
private const int WS_EX_TRANSPARENT = 0x20;
protected override CreateParams CreateParams
{
get
{
CreateParams p = base.CreateParams;
p.ExStyle |= WS_EX_TRANSPARENT;
return p;
}
}
public GDIGraphicsControl()
{
this.Dock = DockStyle.Fill;
}
protected override void OnPaintBackground(PaintEventArgs e)
{
// Do nothing
}
protected override void OnPaint(PaintEventArgs e)
{
for (int i = 0; i < 10; ++i)
{
int alpha = 25 * i;
int yPos = 10 * i;
e.Graphics.FillRectangle(
new SolidBrush(Color.FromArgb(alpha, Color.Green)),
5, 5 + yPos, 100, 10);
}
e.Graphics.FillEllipse(new SolidBrush(Color.Red), 110, 5, 100, 100);
}
}
To analyze the blinking problem I tried to make things simpler. First for debugging purpose I tried to use GDI rendering instead of DirectX. I implemented it such that it will be very similar to the DirectX rendering - especially the Form.SetStyle and the Invalidate() call in every OnPaint() which I thought to be the cause to the problem. The problem do exist also in GDI-only rendering. Here is the GDI-rendering parent control code:
public partial class RenderingForm : Form
{
public RenderingForm()
{
InitializeComponent();
ControlStyles styles =
ControlStyles.AllPaintingInWmPaint |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.ResizeRedraw |
ControlStyles.UserPaint |
ControlStyles.Opaque;
this.SetStyle(styles, true);
Button button = new Button()
{
Text = "Just a button",
Left = 5,
Top = 210,
Width = 200
};
this.Controls.Add(button);
this.Controls.Add(new GDIGraphicsControl());
}
protected override void OnPaintBackground(PaintEventArgs e)
{
// Do nothing
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.Clear(Color.Blue);
this.Invalidate();
base.OnPaint(e);
}
}
I tried to add a simple overlay Button to check if the problem exist when no transparency is used (see in the above code). The button doesn't blink, but instead of the button I see garbage on the screen until resizing the control first time - then the button appears correctly.
I tried to invalidate the child overlay controls but it has no effect. I tried to invalidate it both in parent's OnPaint and in the child OnPaint to create the message-pump rendering effect and it has no effect. Setting the control's style as in parent rendering control didn't resolve the problem and caused the background to blink in black.
I also performed some tries using WPF but the question is long enough for now without hard Airspace issue...
Now for the questions:
Can someone explain how does GDI overlay over DirectX graphics work? Especially I don't understand it because I know that WinForms transparency is working by that the children controls render on the parent's Device Context - and DirectX has a hardware rendering context. Does it mean that the DirectX texture is copied back to software?
Why does overriding the CreateParams causes the Control to blink and how to prevent it?
What are performance cost do those transparency methods (overriding CreateParams, BackColorTransparency = True, Control.SetStyle+override OnPainBackground)? It is of high importance that the underlying graphics will be rendered efficiently but I don't care about the overlay performance (except for lightweight animation).
I've done a LOT of research in this area and I've come to the conclusion that Airspace is the way to go. I've collected sources from numerous projects around the web and put them into a single project that allows you to integrate WPF with XNA. I've also done a version of this that was pure DirectX, but to be honest the XNA version is a lot more straightforward and better suited to C#. I don't have enough room to post all the details here but you can download the demo from my website and probably figure out where to go from there. Good luck!
I’m running into problems when rendering text on my document. Specifically, the text renders too low. I tried filling a rectangle behind the text to see what happens, and I discovered that they appear to render slightly offset:
Here’s the code I used to render the box and text:
_doc.FillRectangle(Colors.LightGray, 36, 72, 37.344, 9);
_doc.DrawString("Lorem", new Font("Arial", 12), Colors.Black,
new Rect(36, 72, 37.344, 9));
I know that the height of the rectangle (9) doesn’t appear to match the height of the font (12), which I thought might have been the problem at first. However, I then did a MeasureString on the font itself and discovered that its height was actually 9 rather than 12 (I used the immediate window for this, which is why it's a pic and not a text block):
Any ideas as to what could be causing it and how to avoid it?
Thanks!
-Ari
There are couple of posts that discuss the WPF text rendering inconsistencies.
One of the other posts: WPF Text rendering problem, stated that SnapToDevicePixels could ruin text rendering if text has been resized to display across pixels. The suggested answer was to keep,
SnapToDevicePixels = True on borders/backgrounds but turn it off for text elements.
As for the current method your are using. Please take a look at one of my earliers posts: Increase bar chart values with button clicks : I have used DrawString() to add a letter within a rectangle. All drawing is done in a Panel.
code:
...
panel1.Paint += new PaintEventHandler(panel1_Paint);
using (Graphics g = this.panel1.CreateGraphics())
{
Brush brush = new SolidBrush(Color.Green);
g.FillRectangle(brush, px, py, 20, 20);
Pen pen = new Pen(new SolidBrush(Color.White));
g.DrawRectangle(pen, px, py, 20, 20);
//add each total5Click into chart block
g.DrawString((total5Times).ToString(), new Font("Arial", 7),
new SolidBrush(Color.AntiqueWhite),
px + 1, py+8, StringFormat.GenericDefault);
pen.Dispose();}
...
I would suggest using the method DrawString Method (String, Font, Brush, RectangleF, StringFormat) and supplying the String Format. After reviewing ComponentOne it appears they are putting together several methods so I may be an issue with the StringFormat default set for the method. I am kind of assuming they are calling the main DrawString method and passing in default params if one was not supplied.
Also be sure to check the section for
Use LineAlignment to specify the vertical alignment of the string.
in the link below
Link to Method
Well, after further research and experimentation there's definitely a bug in the ComponentOne library. Specifically, the overload I happened to have used here returned the wrong hight. If you specific an available width explicitly, you get the correct height. Specifically, this code generates the correct data:
var resultHeight = _doc.MeasureString(text, pdfFont, double.MaxValue).Height;
var resultWidth = _doc.MeasureString(text, pdfFont).Width;
return new Tuple<double,double>(resultHeight, resultWidth);
Note the addition of the third parameter for the height only -- double.MaxValue. The width is correctly calculated in both cases, but the height is only correctly calculated if you provide that double parameter. I chose double.MaxValue in this case simply because I don't know how wide the string is going to turn out to be so I don't want to risk being given a multi-line height.
I am completely new to this forum, and still a beginner on WPF.
I am working on a project that requires the strokes on an inkcanvas to be animated. One of the animations required is "disappearing". I want to make the selected strokes gradually disappear with the click of a button, but appear at the end of the animation.
Since there is no opacity property for stroke, I tried using the ColorAnimation class along with storyboards. I have failed to make this code work, as I cannot target the strokes either using themselves or using their names, since they don't have any.
Right now I am thinking of implementing this system by gradually changing the color of the strokes to the color of the background, and at the end, resetting it back to its initial value. This is a costly loop, but I have no other ideas.
I would appreciate it if there are any other solutions you might share with me.
Thanks in advance.
Edit: I have not answered the comments, as I was dealing with other parts of the same project.
I have tried using the Alpha values that are stored in the DrawingAttributes, but I cannot change the value as it is not a variable. The same goes with RGB values. I have no idea on how to make the strokes disappear in a loop. I have already implemented most of the project, so I just need something to slowly make them disappear. Below you can find an example where I change the stroke itself to animate it.
private int dropOffset = 1;
private void DropAnimation()
{
m = new Matrix();
m.Translate(0, dropOffset);
animStrokes.Transform(m, false);
YChange += dropOffset;
dropOffset += 2;
}
And in another class, I have
public void AnimateStrokes(Dispatcher canvasDispatch)
{
Stopwatch initial = Stopwatch.StartNew();
while (initial.ElapsedMilliseconds < 2000)
{
foreach (Animation ai in AnimationList)
{
ai.animateSelected();
}
canvasDispatch.Invoke(new Action(() => { }), DispatcherPriority.Render);
Thread.Sleep(50);
}
foreach (Animation a in AnimationList)
{
a.undoAnimation();
}
canvasDispatch.Invoke(new Action(() => { }), DispatcherPriority.Render);
}
I know that it's not healthy to pass dispatcher like this, but it suffices for now.
Thanks again in advance.
InkCanvas1.DefaultDrawingAttributes.Color = Color.FromArgb(100, 0, 255, 255);
Might be a bit late but help for others none the less! The 100 is the alpha value which basically acts like an opacity value!! Mess with that and you will be able to change how transparent your strokes are :)
Does anyone know how to colour the editor part (where you can type in the date) for the UltraCalendarCombo (winforms one) programmatically (i.e. without using the Style Library files)?
I want to set the background to a different colour whenever the control has focus but can't find any properties or methods to do this.
Thanks
If I understand you correctly, I believe you can do it one of 2 ways...
// Directly via the BackColor property
ultraCalendarCombo1.BackColor = Color.Blue;
// Using an Appearance object
ultraCalendarCombo1.Appearance = new Infragistics.Win.Appearance { BackColor = Color.Blue };
I've actually figure this one out.
Steve's answer colours the editor part and the drop down part as well.
You need to apply other Appearance properties as well.
// This is a copy from Steve's answer
// Directly via the BackColor property
ultraCalendarCombo1.BackColor = Color.Blue;
// Using an Appearance object
ultraCalendarCombo1.Appearance
= new Infragistics.Win.Appearance { BackColor = Color.Blue };
// Now we set the drop down part to a different colour (Let's say white)
ultraCalendarCombo1.DropDownApperance
= new Infragistics.Win.Appearance { BackColor = Color.White };
I believe you can do it by creating .isl (Infragistics Style Library) files but I wasn't quite sure how to swap these in and out programmatically.