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);
}
Related
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();
}`
I have been watching a couple of videos and I've noticed that you can highlight or set the BackColor for every word it finds in a RichTextBox, I tried doing this with a Label which is what I'm working with on my project but I can't use Label.Find and Label.SelectionBackColor etc. Is there a way I could search a word in my label and highlight it?
You cannot use two different foreground/background colors in a label. You might split up the text in different labels or just use a richtextbox.
Here is a workaround, create a RichTextBox and use it as a label.
Set these properties to make it look like a label:
richTextBox.ReadOnly = true;
richTextBox.BorderStyle = BorderStyle.None;
richTextBox.BackColor = SystemColors.Control; // or whatever your background color is
work around to disable User selection:
richTextBox.Enabled = false;
richTextBox.SelectAll();
richTextBox.SelectionColor = SystemColors.ControlText; // or whatever you want the default text color to be
// you have to set the color or else it will be gray because of Enabled=false
Edit: i just tried it, after SelectAll(); and SelectionColor = SystemColors.ControlText any changing or adding of Text keeps it black (unless the current SelectionStart is at a point of the text where the color is different
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.
How does one set the alignment of text within a chart legend object? I've tried using:
myChartName.Legends["mySeriesName"].Alignment = stringAlignment.Near
With no effect. I've also tried to create custom legend items, again resulting in no effect. Text is ALWAYS centered (along with the series marker) in the legend "box". The only text I have been able to align is the title, but I don't need titles in my application.
My research to date says the legend object is basically a table with (by default) two cells. If that is the case there should be a way to access those cells and manipulate them as table cells. So, what gives? Why can't I access the text alignment properties of the legend object? Clearly, there is something I'm missing, but for the life of me I can't seem to figure this out. Quite frustrating.
Problem solved. The CustomItem approach wasn't working either, so I tried using the LegendCellColumn Class.
I changed the LegendStyle from Column to Row, then added two CellColumns, one for the series symbol and one for the legend text. Set the alignment, margins, and column widths (that turned out to be the trick), and voila; a legend that looks like I want. Here's the code for anyone with a similar issue.
chartSel.Legends[ySeries.Name].CellColumns.Add(new LegendCellColumn("", LegendCellColumnType.SeriesSymbol, ""));
chartSel.Legends[ySeries.Name].CellColumns[0].Alignment = ContentAlignment.TopLeft;
chartSel.Legends[ySeries.Name].CellColumns[0].Margins = new System.Windows.Forms.DataVisualization.Charting.Margins(0, 0, 1, 1);
chartSel.Legends[ySeries.Name].CellColumns[0].MinimumWidth = 250;
chartSel.Legends[ySeries.Name].CellColumns[0].MaximumWidth = 250;
chartSel.Legends[ySeries.Name].CellColumns.Add(new LegendCellColumn("", LegendCellColumnType.Text, ySeries.Name));
chartSel.Legends[ySeries.Name].CellColumns[1].Alignment = ContentAlignment.MiddleLeft;
chartSel.Legends[ySeries.Name].CellColumns[1].Margins = new System.Windows.Forms.DataVisualization.Charting.Margins(0, 0, 1, 1);
chartSel.Legends[ySeries.Name].CellColumns[1].MinimumWidth = 1500;
chartSel.Legends[ySeries.Name].CellColumns[1].MaximumWidth = 1500;
It's probably not the most efficient way to do it, but it works. Technically, the legend symbol and text are still centered in the object, but because I'm forcing the widths of the two columns it has the appearance of being left-justified.
Hopefully, this may help another newbie like me avoid days of consternation.
My understanding is that Legend alignment relates to the Docking property, not really how the text is aligned within the legend. So setting Alignment to Near means positioning the legend box near the Docking direction.
It is quite hard to explain this textually. The MS Chart Samples have a subsection named Chart features -> Legends -> Style and Auto Positioning which will help you play with those two properties and understand how they are meant to work.
For inner legend alignment, you may need to use Legend.CustomItems and define LegendCell individually.
chart.Legends["Default"].CustomItems.Clear();
chart.Legends["Default"].CustomItems.Add(new LegendItem("LegendItem", Color.Red, ""));
chart.Legends["Default"].CustomItems[0].Cells.Add(new LegendCell(LegendCellType.Text, "My text", ContentAlignment.MiddleLeft));
This is described inside the Chart features -> Legends -> Legend Cells section of the samples.
While continuing to try to figure this out I stumbled on this tidbit of info from the following MSDN library page:
http://msdn.microsoft.com/en-us/library/dd456711(v=vs.100).aspx
"NOTE: You cannot adjust the individual legend items and cells in the Chart.Legends collection. To adjust them, use custom legend items."
So, back to the CustomItem route. I've got this code gleaned from several sources (including you, Dominique, thanks):
chartSel.Legends.Add(ySeries.Name);
chartSel.Series[ySeries.Name].IsVisibleInLegend = false;
chartSel.Legends[ySeries.Name].CustomItems.Clear();
LegendItem li = new LegendItem();
li.ImageStyle = LegendImageStyle.Line;
li.Cells.Add(LegendCellType.SeriesSymbol, "", ContentAlignment.TopLeft);
li.Cells[0].BackColor = Color.CornflowerBlue; //color is only to see the cell bounds
li.Cells.Add(LegendCellType.Text, ySeries.Name, ContentAlignment.TopLeft);
li.Cells[1].BackColor = Color.Aquamarine; //color is only to see the cell bounds
chartSel.Legends[ySeries.Name].CustomItems.Add(li);
From what I can find it should work, but it doesn't. It results in a legend object with two cells; the first is empty and the second has left-justified text. I tried to post an image of it, but the system says I'm not yet worthy.
Why there is no line for the series symbol is also a mystery, but that's another problem to solve. The text justification issue is my main concern at the moment. It looks like the text within the cells is left-justified as desired, but the cells themselves are centered in the legend object; not what I wanted. I want those cells to be left-justified in the object too, so the first cell is against the left edge of the legend object.
Ideas?
When adding and removing series from a .net chart control (line chart), how can I retain the existing series colors?
Currently, when I add several series to a chart, they all get colors assigned automatically from the chart palette. But if I then remove the first series, the colors of all of the subsequent series get reset according to the order in the chart palette. Is there any way to stop this happening?
Thanks in advance.
Why don't you just set the chart colors directly and not use a Palette?
Chart.Palette = ChartColorPalette.None;
Chart.Series[0].Color = Color.Green;
etc, etc. This does mean you have to set the color for each series as you add it, but c'est la vie.
You first need to call ApplyPaletteColors to break the automatic coloring scheme.
Then you can apply each series its very own palette color and it will stick:
chart1.ApplyPaletteColors();
series1.Color = series1.Color;
series2.Color = series2.Color;
// or, of course..:
series1.Color = someColor;
series2.Color = someOtherColor;
..
I found that if you add all the series that the chart will use when setting up the chart and then enable or disable the series as you want them shown, it will retain the same colors that were assigned to the series.
I imagine the issue you are running into is actually removing the series from the chart and then adding it back in later as a new series (which I believe is causing it to take the next color in the palette).
In my chart I am working on now, I actually added check boxes to control if series were enabled are disabled and it has been keeping the same color for all the series.
// Assuming I have chart set up with chart area and 3 series.
chart.Series.Add(s1);
chart.Series.Add(s2);
chart.Series.Add(s3);
CheckBox cb1 = new CheckBox();
cb1.Text = s1.Name;
cb.Checked = s1.Enabled;
// Set up action for when checkbox is changed.
cb.CheckedChanged += delegate (object sender, EventArgs e)
{
// Set series enabled property based on check box Checked property
s1.Enabled = cb.Checked;
// Will recalculate the scale to show the remaining series better.
// If you do not want to adjust chart size for remaining series,
// this can be removed.
chart.ChartAreas[s1.ChartArea].RecalculateAxesScale();
// Force redraw of chart area
chart.Invalidate();
};
this.Controls.Add(cb1);
// Repeat for additional check boxes and add to UI
I hope this helps if someone runs across this later.