WPF properties not working correctly in windows 8 - c#

I am having an issue with the BorderThickness or BorderBrush property in Windows 8.
In win7, the code below correctly outlines editControl in a 5px thick read outline, however it does not work in windows 8. I am wondering if there is something deprecated or unsupported in windows 8 now? I cannot find any notion of that on the microsoft documentation.
editControl.BorderThickness = new Thickness(5);
editControl.BorderBrush = Brushes.Red;
Anyone able to help?

I found a workaround using using Adorners.
private class ErrorHighlightAdorner : Adorner
{
public ErrorHighlightAdorner(UIElement adornedElement)
: base(adornedElement)
{
}
protected override void OnRender(DrawingContext drawingContext)
{
Rect sourceRect = new Rect();
FrameworkElement fe = AdornedElement as FrameworkElement;
if (fe != null)
{
sourceRect = new Rect(fe.RenderSize);
}
else
{
sourceRect = new Rect(AdornedElement.DesiredSize);
}
Pen renderPen = new Pen(new SolidColorBrush(Colors.Red), 2.0);
drawingContext.DrawRectangle(null, renderPen, sourceRect);
}
}

Related

GroupBox Border not visible on Server 2016 when using the background color Gainsboro

We use the standard GroupBox and the Flat-Style. The form backgroundcolor is Gainsboro.
On my Windows 7 development machine it looks like this:
However, when running the app in a Windows Server 2016 Machine, it looks like this:
The borders are gone (not visible).
It appears to has something to do with the Background Color, but we're not sure how to fix it. When using a light blue Color, this happens on Server 2016:
Do you guys have any clue, why we can't see the white border with the BG-Color Gainsboro? It doesn't make any sense....
I dont have server 2016 to test it, but maybe overriding the Paint event of the borderColor will solve this problem, here is a custom GroupBox control, you can change borderColor Color inside the constructor.
namespace WindowsFormsApplication5
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
CustomGroupBox gb = new CustomGroupBox();
gb.Location = new Point(5, 5);
gb.Size = new Size(200, 100);
this.Controls.Add(gb);
}
}
public class CustomGroupBox : GroupBox
{
private Color borderColor;
public Color BorderColor
{
get { return this.borderColor; }
set { this.borderColor = value; }
}
public CustomGroupBox()
{
this.borderColor = Color.Red;
}
protected override void OnPaint(PaintEventArgs e)
{
Size tSize = TextRenderer.MeasureText(this.Text, this.Font);
Rectangle borderRect = e.ClipRectangle;
borderRect.Y += tSize.Height / 2;
borderRect.Height -= tSize.Height / 2;
ControlPaint.DrawBorder(e.Graphics, borderRect, this.borderColor, ButtonBorderStyle.Solid);
Rectangle textRect = e.ClipRectangle;
textRect.X += 6;
textRect.Width = tSize.Width;
textRect.Height = tSize.Height;
e.Graphics.FillRectangle(new SolidBrush(this.BackColor), textRect);
e.Graphics.DrawString(this.Text, this.Font, new SolidBrush(this.ForeColor), textRect);
}
}
}

In C# Winforms is there a way to put dotted border around all controls and show grip points upon selection of specific controls at runtime?

I work in a team working on a IDE similar to Visual Studio to develop custom Winform code for our local clients. In our code we have User Controls overridden to make our tasks easier but most of our controls are derived from basic C# Winform Controls.
I currently need help in implementing dotted border around all our controls, with the type of grip points as provided by Visual Studio.
Unselected Controls
Selected Controls
This feature is highly demanded as it can help in aligning without compensation on visual guidelines.
We have currently implemented a dark border around all controls, using
this.BackColor = Color.Black;
this.Height = ComboBox.Height + 4;
Which puts a black border around the generated Controls, which in the above code snippet is a ComboBox.
One member pointed us towards using Margins and Padding as shown in the Microsoft documentation: https://msdn.microsoft.com/library/3z3f9e8b(v=vs.110)
But this is mostly theory and does not seem to help much. the closest thing that has come to solve this problem so far has been an online CodeProject link:
public class MyGroupBox : GroupBox
{
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
ControlPaint.DrawBorder(e.Graphics, ClientRectangle,
Color.Black, BORDER_SIZE, ButtonBorderStyle.Inset,
Color.Black, BORDER_SIZE, ButtonBorderStyle.Inset,
Color.Black, BORDER_SIZE, ButtonBorderStyle.Inset,
Color.Black, BORDER_SIZE, ButtonBorderStyle.Inset);
}
}
I am surprized to not find a close match to my search so far, perhaps i am using the wrong terminology, as I recently got into programming in this domain.
I believe that future online searches are going to be benifitted, if this problem gets solved. Looking forward for pointers form those with experience in this problem. Really appreciate any help in this direction.
I work in a team working on a IDE similar to Visual Studio ....
Developing a custom form designer is not a trivial task and needs a lot of knowledge and a lot of time and I believe the best solution which you can use, is hosting windows forms designer.
It's not just about drawing selection borders:
Each control has it's own designer with specific features, for example some controls like MenuStrip has it's own designer which enables you to add/remove items on designer.
Controls may have some specific sizing and positioning rules. For example some of them are auto-sized like TextBox or docked controls can not be reposition by mouse and so on.
Components are not visible on your form which you may need to edit them.
Some properties are design-time properties.
Some properties are added using extender providers and you need to perform additional tasks to provide a way to change them in your custom designer.
And a lot of other considerations.
Solution 1 - Hosting Windows Forms Designer
To learn more about design time architecture, take a look at Design-Time Architecture. To host windows forms designer in your application, you need to implement some interfaces like IDesignerHost, IContainer, IComponentChangeService, IExtenderProvider, ITypeDescriptorFilterService, IExtenderListService, IExtenderProviderService.
For some good examples you can take a look at:
Hosting Windows Forms Designers by Tim Dawson
Tailor Your Application by Building a Custom Forms Designer with .NET by Sayed Y. Hashimi
You may find this post useful:
Hosting Windows Forms Designer - Serialize and Deserialize designer at runtime
The post contains a working example on how to host windows forms designer at run-time and generate code:
Solution 2 - Drawing selection border over a transparent panel
While I strongly recommend using the first solution, but just for learning purpose if you want to draw selection border around controls, you can add the forms which you want to edit as a control to the host form, then put a transparent panel above the form. Handle Click event of transparent Panel and find the control under mouse position and draw a selection border around it on transparent panel like this:
In the example, I just created a transparent panel and drew selection border. It's just an example and performing sizing and positioning is out of scope of the example. It's just to show you how you can draw selection border around controls. You also can use the idea to create a SelctionBorder control and encapsulate sizing and positioning logic in the control and instead of drawing the borders, add an instance of SelectionBorder control to transparent panel and in its sizing and positioning events, change corresponding control coordinates.
Please pay attention it's just an example and in a real designer environment you should consider a lot of important things.
Transparent Panel
using System.Windows.Forms;
public class TransparentPanel : Panel
{
const int WS_EX_TRANSPARENT = 0x20;
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle = cp.ExStyle | WS_EX_TRANSPARENT;
return cp;
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
}
}
Host Form
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
public partial class HostForm : Form
{
private Panel containerPanel;
private TransparentPanel transparentPanel;
private PropertyGrid propertyGrid;
public HostForm()
{
this.transparentPanel = new TransparentPanel();
this.containerPanel = new Panel();
this.propertyGrid = new PropertyGrid();
this.SuspendLayout();
this.propertyGrid.Width = 200;
this.propertyGrid.Dock = DockStyle.Right;
this.transparentPanel.Dock = System.Windows.Forms.DockStyle.Fill;
this.transparentPanel.Name = "transparentPanel";
this.containerPanel.Dock = System.Windows.Forms.DockStyle.Fill;
this.containerPanel.Name = "containerPanel";
this.ClientSize = new System.Drawing.Size(450, 210);
this.Controls.Add(this.transparentPanel);
this.Controls.Add(this.propertyGrid);
this.Controls.Add(this.containerPanel);
this.Name = "HostForm";
this.Text = "Host";
this.Load += this.HostForm_Load;
this.transparentPanel.MouseClick += this.transparentPanel_MouseClick;
this.transparentPanel.Paint += this.transparentPanel_Paint;
this.ResumeLayout(false);
}
private void HostForm_Load(object sender, EventArgs e)
{
this.ActiveControl = transparentPanel;
/**************************************/
/*Load the form which you want to edit*/
/**************************************/
var f = new Form();
f.Location = new Point(8, 8);
f.TopLevel = false;
this.containerPanel.Controls.Add(f);
SelectedObject = f;
f.Show();
}
Control selectedObject;
Control SelectedObject
{
get { return selectedObject; }
set
{
selectedObject = value;
propertyGrid.SelectedObject = value;
this.Refresh();
}
}
void transparentPanel_MouseClick(object sender, MouseEventArgs e)
{
if (this.Controls.Count == 0)
return;
SelectedObject = GetAllControls(this.containerPanel)
.Where(x => x.Visible)
.Where(x => x.Parent.RectangleToScreen(x.Bounds)
.Contains(this.transparentPanel.PointToScreen(e.Location)))
.FirstOrDefault();
this.Refresh();
}
void transparentPanel_Paint(object sender, PaintEventArgs e)
{
if (SelectedObject != null)
DrawBorder(e.Graphics, this.transparentPanel.RectangleToClient(
SelectedObject.Parent.RectangleToScreen(SelectedObject.Bounds)));
}
private IEnumerable<Control> GetAllControls(Control control)
{
var controls = control.Controls.Cast<Control>();
return controls.SelectMany(ctrl => GetAllControls(ctrl)).Concat(controls);
}
void DrawBorder(Graphics g, Rectangle r)
{
var d = 4;
r.Inflate(d, d);
ControlPaint.DrawBorder(g, r, Color.Black, ButtonBorderStyle.Dotted);
var rectangles = new List<Rectangle>();
var r1 = new Rectangle(r.Left - d, r.Top - d, 2 * d, 2 * d); rectangles.Add(r1);
r1.Offset(r.Width / 2, 0); rectangles.Add(r1);
r1.Offset(r.Width / 2, 0); rectangles.Add(r1);
r1.Offset(0, r.Height / 2); rectangles.Add(r1);
r1.Offset(0, r.Height / 2); rectangles.Add(r1);
r1.Offset(-r.Width / 2, 0); rectangles.Add(r1);
r1.Offset(-r.Width / 2, 0); rectangles.Add(r1);
r1.Offset(0, -r.Height / 2); rectangles.Add(r1);
g.FillRectangles(Brushes.White, rectangles.ToArray());
g.DrawRectangles(Pens.Black, rectangles.ToArray());
}
protected override bool ProcessTabKey(bool forward)
{
return false;
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
this.Refresh();
}
}
Some caution would be appropriate here, modeling a UI designer after the Winforms designer is an easy decision, actually implementing it is a job that can keep you occupied for many months. Discovering that you cannot paint outside the control bounds is indeed the very first obstacle you'll run into, many more like that.
The first shortcut you might consider is to draw place-holders for the controls so you don't depend on the Control class. Works fine as long as it doesn't have to look too closely like the real control (i.e. give up on WYSIWYG) and you don't have to resize them.
But you'll surely dismiss that. You then have to do the same thing the Winforms designer does, you have to overlay a transparent window on top of the design surface. You can draw anything you want on that overlay and it provides automatic mouse and keyboard isolation so the control itself is completely oblivious of the design-time interaction. Find examples of such an overlay in this post and this post.
Last but not least, it is worth mentioning that you can leverage the existing Winforms designer in your own projects as well. You have to implement IDesignerHost. And a bunch more, unfortunately the abstraction level is fairly high and the MSDN docs rather brief. Best thing to do is to work from a sample that shows a full-featured designer. This KB article has the link. Code is excellent and well documented, you get an almost complete designer with toolbox and Properties window which de/serializes the design from/to XML and can generate C# and VB.NET code. Do look past the garish UI, it doesn't enable Visual Styles and color choices are the kind that I would make :) Making it pretty wasn't the point of the code sample.
I Have Created I windows Form Application Hope this will Help you
BackEnd C# Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Paint += new PaintEventHandler(this_Paint);
}
private void this_Paint(object sender, PaintEventArgs e)
{
Pen pen = new Pen(Color.Green, 2.0F);
pen.DashStyle = DashStyle.Dash;
foreach (Control c in groupBox1.Controls)
{
e.Graphics.DrawRectangle(pen, (groupBox1.Location.X + c.Location.X)-1, (groupBox1.Location.Y + c.Location.Y)-1, c.Width + 2, c.Height + 2);
}
pen.Dispose();
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}
Designer C# Code
namespace WindowsFormsApplication2
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.comboBox1 = new System.Windows.Forms.ComboBox();
this.comboBox2 = new System.Windows.Forms.ComboBox();
this.comboBox3 = new System.Windows.Forms.ComboBox();
this.comboBox4 = new System.Windows.Forms.ComboBox();
this.groupBox1.SuspendLayout();
this.SuspendLayout();
//
// groupBox1
//
this.groupBox1.BackColor = System.Drawing.Color.Transparent;
this.groupBox1.Controls.Add(this.comboBox4);
this.groupBox1.Controls.Add(this.comboBox3);
this.groupBox1.Controls.Add(this.comboBox2);
this.groupBox1.Controls.Add(this.comboBox1);
this.groupBox1.Location = new System.Drawing.Point(33, 36);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(193, 184);
this.groupBox1.TabIndex = 0;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "groupBox1";
//
// comboBox1
//
this.comboBox1.FormattingEnabled = true;
this.comboBox1.Location = new System.Drawing.Point(36, 40);
this.comboBox1.Name = "comboBox1";
this.comboBox1.Size = new System.Drawing.Size(121, 21);
this.comboBox1.TabIndex = 0;
//
// comboBox2
//
this.comboBox2.FormattingEnabled = true;
this.comboBox2.Location = new System.Drawing.Point(36, 67);
this.comboBox2.Name = "comboBox2";
this.comboBox2.Size = new System.Drawing.Size(121, 21);
this.comboBox2.TabIndex = 1;
//
// comboBox3
//
this.comboBox3.FormattingEnabled = true;
this.comboBox3.Location = new System.Drawing.Point(36, 94);
this.comboBox3.Name = "comboBox3";
this.comboBox3.Size = new System.Drawing.Size(121, 21);
this.comboBox3.TabIndex = 1;
//
// comboBox4
//
this.comboBox4.FormattingEnabled = true;
this.comboBox4.Location = new System.Drawing.Point(36, 121);
this.comboBox4.Name = "comboBox4";
this.comboBox4.Size = new System.Drawing.Size(121, 21);
this.comboBox4.TabIndex = 1;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 261);
this.Controls.Add(this.groupBox1);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.groupBox1.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.ComboBox comboBox1;
private System.Windows.Forms.ComboBox comboBox4;
private System.Windows.Forms.ComboBox comboBox3;
private System.Windows.Forms.ComboBox comboBox2;
}
}
Make GroupBox1 backgroundcolour 'Transparent' because I am drawing on Form not on
GroupBox
You Can also Create Border on Selected Controls by Adding if(c is ComboBox)
or if (c.Name == "comboBox1")
in foreach loop
!! Change the Color According to your Need !!
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
hatchedPen = (Pen)SystemPens.ControlDarkDark.Clone();
hatchedPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// Clear any existing grab handles
using (Graphics g = Graphics.FromHwnd(this.Handle))
{
foreach (Control ctrl in Controls)
{
var rect = GetGrabBounds(ctrl);
g.FillRectangle(SystemBrushes.ButtonFace, rect);
}
}
// Need to draw grab handles?
if (ActiveControl != null && e.ClipRectangle.IntersectsWith(GetGrabBounds(ActiveControl)))
{
DrawGrabHandles(ActiveControl);
}
}
private void DrawGrabHandles(Control ctrl)
{
using (Graphics g = Graphics.FromHwnd(this.Handle))
{
Rectangle bounds = GetGrabRect(ctrl);
g.DrawRectangle(hatchedPen, bounds);
foreach (Point pt in new Point[]
{
new Point(bounds.Left, bounds.Top),
new Point(bounds.Left + bounds.Width / 2, bounds.Top),
new Point(bounds.Right, bounds.Top),
new Point(bounds.Left, bounds.Top + bounds.Height / 2),
new Point(bounds.Right, bounds.Top + bounds.Height / 2),
new Point(bounds.Left, bounds.Bottom),
new Point(bounds.Left + bounds.Width / 2, bounds.Bottom),
new Point(bounds.Right, bounds.Bottom),
})
{
Rectangle r = new Rectangle(pt, new Size(5, 5));
r.X = r.X - 2;
r.Y = r.Y - 2;
g.FillRectangle(SystemBrushes.ButtonFace, r);
g.DrawRectangle(SystemPens.ControlDarkDark, r);
}
}
}
private static Rectangle GetGrabRect(Control ctrl)
{
var result = ctrl.Bounds;
result = Rectangle.Inflate(result, 4, 4);
result.X--;
result.Y--;
return result;
}
private static Rectangle GetGrabBounds(Control ctrl)
{
var result = GetGrabRect(ctrl);
result.Inflate(4, 4);
return result;
}
private Pen hatchedPen;
}

WPF hit test on custom control does not work

The following custom control
public class DummyControl : FrameworkElement
{
private Visual visual;
protected override Visual GetVisualChild(int index)
{
return visual;
}
protected override int VisualChildrenCount { get; } = 1;
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
{
var pt = hitTestParameters.HitPoint;
return new PointHitTestResult(visual, pt);
}
public DummyControl()
{
var dv = new DrawingVisual();
using (var ctx = dv.RenderOpen())
{
var penTransparent = new Pen(Brushes.Transparent, 0);
ctx.DrawRectangle(Brushes.Green, penTransparent, new Rect(0, 0, 1000, 1000));
ctx.DrawLine(new Pen(Brushes.Red, 3), new Point(0, 500), new Point(1000, 500));
ctx.DrawLine(new Pen(Brushes.Red, 3), new Point(500, 0), new Point(500, 1000));
}
var m = new Matrix();
m.Scale(0.5, 0.5);
RenderTransform = new MatrixTransform(m);
//Does work; but only the left top quater enters hit test
//var hv = new HostVisual();
//var vt = new VisualTarget(hv);
//vt.RootVisual = dv;
//visual = hv;
//Never enters hit test
visual = dv;
}
}
The xaml
<Window x:Class="MyNamespace.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MyNamespace"
mc:Ignorable="d">
<Border Width="500" Height="500">
<local:DummyControl />
</Border>
</Window>
Display a green area with two red coordinate lines through the center. But its hit testing behavior is not understandable for me.
I put a breakpoint in the method HitTestCore but it never hits.
If I un-comment the code to use HostVisual and VisualTarget instead, it hits but only when the mouse is in the left top quater (indiciaed by the red lines given above)
How could the above being explained and how can I could make it work as expected (enters hit test on full range)?
(Originally, I just wanted to handle mouse events on the custom control. Some existing solutions pointed me to overriding the HitTestCore method. So if you could provide any idea that can let me handle mouse events, I don't have to make HitTestCore method working.)
Update
Clemen's answer is good if I decided to use DrawingVisual. However, when I use HostVisual and VisualTarget it is Not working without overriding HitTestCore, and even I do this, still only the top left quater will receive mouse events.
The original question also includes explainations. Also, the use of HostVisual allows me to run the render (time consuming in my real case) in another thread.
(Let me hightlight the code using HostVisual above)
//Does work; but only the left top quater enters hit test
//var hv = new HostVisual();
//var vt = new VisualTarget(hv);
//vt.RootVisual = dv;
//visual = hv;
Any idea?
UPDATE #2
Clemen's new answer is still not working for my purpose. Yes, all the visual area receives hit test. However, what I wanted is to have the full viewport to receive hit test. Which, in his case, is the blank area as he scaled the full visual to the visual area.
In order to establish a visual tree (and thus make hit testing work by default), you also have to call AddVisualChild. From MSDN:
The AddVisualChild method sets up the parent-child relationship
between two visual objects. This method must be used when you need
greater low-level control over the underlying storage implementation
of visual child objects. VisualCollection can be used as a default
implementation for storing child objects.
Besides that, your control should re-render whenever its size changes:
public class DummyControl : FrameworkElement
{
private readonly DrawingVisual visual = new DrawingVisual();
public DummyControl()
{
AddVisualChild(visual);
}
protected override int VisualChildrenCount
{
get { return 1; }
}
protected override Visual GetVisualChild(int index)
{
return visual;
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
using (var dc = visual.RenderOpen())
{
var width = sizeInfo.NewSize.Width;
var height = sizeInfo.NewSize.Height;
var linePen = new Pen(Brushes.Red, 3);
dc.DrawRectangle(Brushes.Green, null, new Rect(0, 0, width, height));
dc.DrawLine(linePen, new Point(0, height / 2), new Point(width, height / 2));
dc.DrawLine(linePen, new Point(width / 2, 0), new Point(width / 2, height));
}
base.OnRenderSizeChanged(sizeInfo);
}
}
When your control uses a HostVisual and a VisualTarget it would still have to re-render itself when its size changes, and also call AddVisualChild to establish a visual tree.
public class DummyControl : FrameworkElement
{
private readonly DrawingVisual drawingVisual = new DrawingVisual();
private readonly HostVisual hostVisual = new HostVisual();
public DummyControl()
{
var visualTarget = new VisualTarget(hostVisual);
visualTarget.RootVisual = drawingVisual;
AddVisualChild(hostVisual);
}
protected override int VisualChildrenCount
{
get { return 1; }
}
protected override Visual GetVisualChild(int index)
{
return hostVisual;
}
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParams)
{
return new PointHitTestResult(hostVisual, hitTestParams.HitPoint);
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
using (var dc = drawingVisual.RenderOpen())
{
var width = sizeInfo.NewSize.Width;
var height = sizeInfo.NewSize.Height;
var linePen = new Pen(Brushes.Red, 3);
dc.DrawRectangle(Brushes.Green, null, new Rect(0, 0, width, height));
dc.DrawLine(linePen, new Point(0, height / 2), new Point(width, height / 2));
dc.DrawLine(linePen, new Point(width / 2, 0), new Point(width / 2, height));
}
base.OnRenderSizeChanged(sizeInfo);
}
}
You could now set a RenderTransform and still get correct hit testing:
<Border>
<local:DummyControl MouseDown="DummyControl_MouseDown">
<local:DummyControl.RenderTransform>
<ScaleTransform ScaleX="0.5" ScaleY="0.5"/>
</local:DummyControl.RenderTransform>
</local:DummyControl>
</Border>
This will work for you.
public class DummyControl : FrameworkElement
{
protected override void OnRender(DrawingContext ctx)
{
Pen penTransparent = new Pen(Brushes.Transparent, 0);
ctx.DrawGeometry(Brushes.Green, null, rectGeo);
ctx.DrawGeometry(Brushes.Red, new Pen(Brushes.Red, 3), line1Geo);
ctx.DrawGeometry(Brushes.Red, new Pen(Brushes.Red, 3), line2Geo);
base.OnRender(ctx);
}
RectangleGeometry rectGeo;
LineGeometry line1Geo, line2Geo;
public DummyControl()
{
rectGeo = new RectangleGeometry(new Rect(0, 0, 1000, 1000));
line1Geo = new LineGeometry(new Point(0, 500), new Point(1000, 500));
line2Geo = new LineGeometry(new Point(500, 0), new Point(500, 1000));
this.MouseDown += DummyControl_MouseDown;
}
void DummyControl_MouseDown(object sender, MouseButtonEventArgs e)
{
}
}

WPF Drawing context

In my wpf application i am drawing a lot of geometries as below. My requirement is to change the color of drawingvisual with out redrawing it? any possibilities in wpf?
using (DrawingContext vDrawingContext = vDrawingVisual.RenderOpen())
{
StreamGeometry vGeom = GetCutGeometry(mLength, mWidth);
vDrawingContext.DrawGeometry(mBackGroundBrush, ForeGroundPen, vGeom);
vDrawingContext.Close();
VisualChildren.Add(vDrawingVisual);
}
How could be mBackGroundBrush dyamic colors?
Provided that mBackGroundBrush is a modifiable SolidColorBrush (i.e. it is created in your application and none of the predefined brushes), you could simply change its Color property. That will change the fill color of each drawn geometry with redrawing.
private SolidColorBrush mBackGroundBrush = new SolidColorBrush(Colors.Black);
...
mBackGroundBrush.Color = Colors.Red;
or
mBackGroundBrush.Color = Color.FromArgb(255, 255, 0, 0);
I have done one work around as below. seems working.
///Kept as arefrence while initial drawing phase.
private DrawingVisual mDrawingVisual = null;
if (null != mDrawingVisual)
{
using (DrawingContext vDrawingContext = mDrawingVisual.RenderOpen())
{
DrawingGroup vDrawingGroup = VisualTreeHelper.GetDrawing(mDrawingVisual);
if (null != vDrawingGroup)
{
foreach (Drawing vDrawing in vDrawingGroup.Children)
{
GeometryDrawing vGeometryDrawing = vDrawing as GeometryDrawing;
if (null != vGeometryDrawing)
{
vGeometryDrawing.Brush = mBackGroundBrush;
}
}
}
vDrawingContext.DrawDrawing(vDrawingGroup);
vDrawingContext.Close();
}
}

OnPaint Paint Issue

I have created a custom checkBox to increase the height of the rectangle of the checkbox. I have override the OnPaint method as given below. When I make the control transparent, background becomes white, instead of transparent. What could be the issue?
protected override void OnPaint(PaintEventArgs pevent)
{
base.OnPaint(pevent);
int h = this.Height;
if (BackColor == Color.Transparent)
{
pevent.Graphics.Clear(this.Parent.BackColor);
}
else
{
pevent.Graphics.Clear(BackColor);
}
Rectangle rc = new Rectangle(new Point(0, 0), new Size(h, h));
ControlPaint.DrawCheckBox(pevent.Graphics, rc,
this.Checked ? ButtonState.Checked : ButtonState.Normal);
SizeF stringMeasure = pevent.Graphics.MeasureString(Text, Font);
int topOffset = (int)(ClientRectangle.Height - stringMeasure.Height) / 2;
pevent.Graphics.DrawString(Text, Font, new SolidBrush(ForeColor), this.Height, topOffset);
}
I am not sure if you derived your checkbox from the given class CheckBox or you derived it from Control. If you derived from control, you should add in the constructor the following line:
public CustomChecBox()
: base()
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
}
Note, that there is also a function called OnPaintBackground(...) which you can override, but you should not need to to this.
In your OnPaint()-function, you should replace
if (BackColor == Color.Transparent)
{
pevent.Graphics.Clear(this.Parent.BackColor);
}
else
{
pevent.Graphics.Clear(BackColor);
}
with
pevent.Graphics.Clear(BackColor);
or
pevent.Graphics.FillRectangle(new SolidBrush(this.BackColor), this.ClientRectangle);
But this is, what happens in OnPaintBackground(...). If you set the BackColor to transparent and you added the SetStyle-Methid in the contructor, then your control should be really transparent. I hope this helps.

Categories