and thanks for taking a peek at my conundrum.
I am trying to write a series of strings to an image as overlays, then later be able to come back and move, or delete one of them selectively using WPF framework...
I've been looking into the FindVisualChildren function, but for the moment cant make heads or tails of how to detect the proximity to the mouse (for selectivity), or actually detect one of my created strings (Perhaps I should be making them dynamic 'Label' elements...????)
Insomnia sucks, and my brains are turning to mush.
TIA for any advice!
Okay, sorry for the lack of sample code, been a long night... well two nights actually (See earlier comment about insomnia)
public void WriteTextToImage(Point position)
{
ImageSource bitmapSource = imgFrame.Source;
var vis = new DrawingVisual();
using (DrawingContext drawingContext = vis.RenderOpen())
{
// Set the pen color... Why is this called a brush if it's for
// writing? perhaps I should overload it and call it crayon?
SolidColorBrush brush = new SolidColorBrush((Color)cpColor.SelectedColor);
drawingContext.DrawImage(bitmapSource, new Rect(0, 0, imgFrame.Source.Width, imgFrame.Source.Height));
//Write some pretty words, (actually print some general stuff)
drawingContext.DrawText(new FormattedText(tbCurrentLabel.Text, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, new Typeface("Arial"), slFontSize.Value, brush),position);
}
//Slap this puppy to the screen
var image = new DrawingImage(vis.Drawing);
//Iterate the label text to the next digit or value
IterateLabel();
}
Basically what will happen is the user will click the screen in several places to make marks on the image for printing, but I want to include support to move those marks, and delete them as needed.
I hope this explains what I am trying to accomplish a little better.
Thanks again!
Excellent! thanks NineBerry, I figured it was going to be something like that. I was originally thinking a label, but the textblock worked perfectly.
Here's the updated code showing how I am getting it done now.
public void WriteTextToImage(Point position)
{
SolidColorBrush brush = new SolidColorBrush((Color)cpColor.SelectedColor);
//Get something to write on (not an old receipt...)
TextBlock textBlock = new TextBlock();
//Say something useful... well something atleast...
textBlock.Text = tbCurrentLabel.Text;
textBlock.FontSize = slFontSize.Value;
textBlock.Foreground = brush;
Canvas.SetLeft(textBlock, position.X);
Canvas.SetTop(textBlock, position.Y);
canvas.Children.Add(textBlock);
//Need to update the canvas, was not seeing children before doing this.
canvas.UpdateLayout();
//Iterate the label text
IterateLabel();
}`
Related
The question I have seems to be simple but I can't find an answer around the Internet for that and even trying around did not help me.
I just want to change the color of a Legend (from a Series). I know how to change the text color but I need to change the color of that marker.
chart1.Legends["1"].ForeColor = Color.Transparent;
chart1.Legends["1"].BackColor = Color.Transparent;
does not help
Is this possible?
Thank you!
EDIT:
I want to change the blue color to another. Hope this is more clear now.
The markers show the ChartType and the Color of all the Series.
Unfortunately the default LegendItems anre hidden and can't be changed, only expanded.
So your best bet, except avoiding the issue by picking a a different green, (if that is why you want to change the blue) would be to clear or disable the default Legend and create a new one from scratch.
For this you can style all sorts of things including setting MarkerStyles and also Bitmaps you create on the fly..
Here and here are two examples that show you how to do it..
And here is one with a rather extended custom Legend
Instead of creating a new Legend you can also hide the LegendItem for a Series
series1.IsVisibleInLegend = true;
and add a new one but it will be added at the end..
Here is an example of adding a simple LegendItem:
void AddLegendItem(Legend L, Series s, Color mc)
{
LegendItem lit = new LegendItem();
lit.BorderColor = mc;
lit.Color = mc;
lit.SeriesName = s.Name;
lit.Name = s.Name;
L.CustomItems.Add(lit);
}
How do I do the following I'm not asking for specific code but I need some direction as I have been racking my brains on this for weeks. Simply I want to make a map of the eg. united states and each state is a different picture or area that can be moused over and clicked. I tried playing with png and transparencies but I'm at a dead end. More ambitiously I'd like to drag labels with state capitals over each state and drop them there then have a process where if the label/capital matches the state it correct else it's not.
I've tried GIS(?) I want to do this C# but I can't get traction how to do it so far. Can anyone help? Is this too difficult in C#? SHould i be using another approach? Please what is the approach?
The good news first: The programming part is not so hard and even with good old Winforms you can do the core checks in a few lines. The clickable areas can't be Buttons in Winforms, however.
Here are two solutions:
Solution 1 : You can define a list of areas, called regions and test if one got clicked.
Here is a start: I define a very simple Rectangle Region and a not so simple Polygon Region and test on each click if one was hit. If it was hit I output its data into the Form's title text:
//..
using System.Drawing.Drawing2D;
//..
public Form1()
{
InitializeComponent();
// most real states don't look like rectangles
Region r = new Region(new Rectangle(0, 0, 99, 99));
regions.Add(r);
List<int> coords = new List<int>() {23,137, 76,151, 61,203,
117,283, 115,289, 124,303, 112,329, 76,325, 34,279, 11,162};
List<Point> points = new List<Point>();
for (int i = 0; i < coords.Count ; i += 2)
points.Add(new Point(coords[i], coords[i+1]));
byte[] fillmodes = new byte[points.Count];
for (int i = 0 ; i < fillmodes.Length; i++) fillmodes[i] = 1;
GraphicsPath GP = new GraphicsPath(points.ToArray(), fillmodes);
regions.Add(r);
}
List<Region> regions = new List<Region>();
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
using (Graphics G = pictureBox1.CreateGraphics() )
foreach(Region r in regions)
{
Region ri = r.Clone();
ri.Intersect(new Rectangle(e.X, e.Y, 1, 1));
if (!ri.IsEmpty(G)) // hurray, we got a hit
{ this.Text = r.GetBounds(G).ToString(); break; }
}
}
The regions in the test programm are not visible. For testing you may want to add something like this:
private void button1_Click(object sender, EventArgs e)
{ // paint a non-persistent filling
using (Graphics G = pictureBox1.CreateGraphics())
foreach (Region r in regions)
{ G.FillRegion(Brushes.Red, r); }
}
But now for the bad news: You can define regions to be complicated polygons that look like real states, however that is a lot of work! There are ready-made image map editors out there in the web for making clickable maps on websites. Your best course might be to use one of these to create all those polygons and then convert the html output to a list of points you can read into your program. You may even get lucky and find ready image maps for the USA, but I haven't looked..
Update: There are many image maps of the USA out there. One is even on wikipedia. Converting these coordinates to fit your map will be a task but lot easier than creating them from scratch, imo. I have changed the code to include one list of cordinates from the wikipedia source. Guess the state!
I have implmented a program that lets you click on a state and displays the name in 78 lines of code, excluding the text file with the 50 states.
Solution 2:
Instead of a list of polygons you can prepare a colored map and use the colors as keys into a Dictionary<Color, string> or Dictionary<Color, StateInfo>. You must make sure that each state has one unique color and that the image is not compressed as jpeg, which would introduce artifacts and mess up the key mapping.
Next you map each color to the related info; this is the real work because you must know those states to create the Dictionary ;-)
Finally you can look up the clicked color in the Dictionary you have created:
Color c = ((Bitmap) pictureBox1.Image).GetPixel(e.X, e.Y)
string StateName = stateDictionary[c];
If you are using a class or struct as your value in the dictionary you can include the capital etc..
You can zoom but must scale the click location accordingly; you can even display a geographical Image if you look up the key color not in the PictureBox but in an invisible color code bitmap.
All in all an even simpler solution imo.. your pick!
Once you got that working, you can play with drag&drop. Here you'll want to test on DragDrop or maybe on Mouseup to see where you have dropped the Label.
This is a nice project and well worth of creating a few classes to make things easier and more expandable..!
For real Buttons you may get lucky with WPF.
I am using the dynamic data display WPF chart. I have a requirement to display a label next to every point on the curves plotted on the chart.
The exact functionality is as follows:
Every curve has a an object that holds its data and a description that inculdes color, marker shape etc. It also tell me whether the labels must be visible for that particular curve.
There is also an option using a checkbox to hide/show the labels for all points on all the curves on the plot.
There is a third option where a user can left click on the marker and see a label next to it.
Now, I previously implemented it by adding labels along with the ElementMarkerPointGraph for each point and setting the visibility of the labels. I know there is a massive performance hit with this approach.
I am now looking to create a solution where I can render text directly to the canvas at a location that I provide. I also need help with the removing the text from the canvas.
Is there a way of adding text natively to the canvas? What is the most efficient way to do so?
EDIT: I need to move the text around as the plotter zooms. I already know when the plotter zooms, I need to be able to move the text to the appropriate location.
I'm not sure whether this will give you the zooming purpose but the code below can be used to add text inside a canvas..I got it from a site while googling.
private void Text(double x, double y, string text, Color color)
{
TextBlock textBlock = new TextBlock();
textBlock.Text = text;
textBlock.Foreground = new SolidColorBrush(color);
Canvas.SetLeft(textBlock, x);
Canvas.SetTop(textBlock, y);
canvasObj.Children.Add(textBlock);
}
OK. My exact implementation can't be put up here. But I can provide some idea of how to do it.
So create a simple user control that derives from Canvas.
class CustomCanvas : Canvas
{
protected override void OnRender(DrawingContext dc)
{
FormattedText someFormattedText = new FormattedText(someText, System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
someTypeFace, someFontSize, someColor);
dc.DrawText(someFormattedText, new Point(15, 15));
}
}
You can seal the class, if you do not want it subclassed/overriden further.
That's about it. You can check out the other methods available with the drawing context to do some other stuff. :)
I figured it out myself. I'll be overriding the OnRender method to handle this. I can draw text using the drawing context.
I am using stylus input to draw lines in a canvas. I want to change the color of the stroke with the pen pressure. so I used:
DrawingAttributes dattribute = new DrawingAttributes();
inkcan.EditingMode = InkCanvasEditingMode.Ink;
if (stylusInput.pressureFactor < 0.5)
dattribute.Color = Colors.Red;
else
dattribute.Color = Colors.Blue;
inkcan.DefaultDrawingAttributes = dattribute;
but I have found that the color changes only when I lift off and retouch the pen to tablet surface. I am not sure how to fix that problem.
Any help would be greatly appreciated.
Look at this question: InkCanvas Eraser
In the MSDN it states:
If you change the EraserShape, the cursor rendered on the InkCanvas is
not updated until the next EditingMode change.
The effect you are experiencing might be caused by the EditingMode being changed when you pull the pen off the canvas and put it back down.
If so, you could toggle the EditingMode property as I suggested in the linked answer.
EDIT
Have a look at this a 3rd down it says:
Off course, life is never as simple as that, so there is one more
little issue to handle. Apparently, the InkCanvas uses different
renderers for the final result compared to while the strokes are being
drawn. To show a transparency based on the pressure while the
drawing action is still in progress, we need to use the protected
property called DyamicRenderer which gets/sets the object used to
render the strokes on a drawing context while the stroke is being
drawn. This rendering object must be a descendent of DynamicRenderer.
All you need to do here is override the OnDraw method and change the
brush that is used. When you assign a new value to this property, the
InkCanvas actually changes an internal 'PlugIn list' which is called
whenever data is entered using the stylus.
This might be it.
The if condition is evaluated only once, so there is no reason for the colour to change while you are drawing. Unfortunately, there seems to be no "onpressurechanged" event, so you would probably have to set up a loop that checks the pressure every x milliseconds and adjusts the colour accordingly.
Since you don't want to freeze the UI, you would either need to run it in another thread and delegate the colour change back to the UI thread, or you can queue the pressure checks onto the window dispatcher with "applicationIdle" priority. This would look something like:
void checkPressure(InkCanvas inkcan)
{
//return if touch is lifted code here
DrawingAttributes dattribute = new DrawingAttributes();
if (stylusInput.pressureFactor < 0.5)
dattribute.Color = Colors.Red;
else
dattribute.Color = Colors.Blue;
inkcan.DefaultDrawingAttributes = dattribute;
this.Dispatcher.BeginInvoke(new MyPressureDelegate(checkPressure), DispatcherPriority.ApplicationIdle, inkcan);
}
assuming your stylusInput shares scope with the function, of course. Otherwise you'd need to pass it in along with the canvas in an object array.
What's the quickest way to show a red/green light indicator on a C# form?
I originally thought about using radio buttons, but not sure how to set the color of the dot, only the foreground/background text.
Then I thought about drawing a circle. Couldn't find a toolbox shape for that, and didn't want to write code just to draw the circle.
Basically, I'm writing a little application specific monitor, that shows a red light if certain services are down, or certain web services are not responding.
This is what I have so far using a square button instead of a circle. The code is just what I want, I just want a round shape.
if (allGood)
{
btnIISIndicator.BackColor = Color.Green;
}
else
{
btnIISIndicator.BackColor = Color.Red;
}
This is simple, just use System.Windows.Shapes for the object and System.Windows.Media.Brushes for the colors.
For a circle you can do the following:
System.Windows.Shapes.Ellipse circle = new System.Windows.Shapes.Ellipse();
circle.Height = 20; //or some size
circle.Width = 20; //height and width is the same for a circle
circle.Fill = System.Windows.Media.Brushes.Red;
Then you can make a function to do your check for red and green.
Also, you can use hex values for the colors as well:
circle.Fill = new System.Windows.Media.SolidColorBrush((Color)ColorConverter.ConvertFromString("#RRGGBB"));
Not exactly related to the question at hand, but your code could be shortened somewhat using the ternary operator as such:
btnIISIndicator.BackColor = allGood ? Color.Green : Color.Red;
But that all depends on your (or your organization's) definition of readability and maintainability.
I would just make a panel or PictureBox and set the Background image to that of a red/green light. Either make the images in PhotoShop/PaintShop/MS Paint or download some stock images off the web.
Whenever the status changes, just swap the image out.
just try this it works for me.
SolidColorBrush solidColor=new SolidColorBrush();
solidColor.Color=Colors.Red;
ellips_circle.Fill=solidColor;
Use an image, but theres some great icons available here so you dont have to actually make some.
Create red and green bitmaps and use the PictureBox control to show the bitmaps.
I just use some standard images and put them in a picturebox. works great on our apps.
I simply used a non enabled button as indicator since I did not manage to install the WinUI for shapes. Same suggestion as question but simplified.
indicatorButton.Enabled = false;
...
if (allGood)
{
indicatorButton.BackColor = Color.Green;
indicatorButton.Text = "On";
}
else
{
indicatorButton.BackColor = Color.Red;
indicatorButton.Text = "Off";
}