The default LineSeries implementation orders data points by independed value. This gives me strange results for data like this:
Is it possible to plot a line series where lines are drawn between the points in the original order?
I currently solved this by inheriting from LineSeries:
class UnorderedLineSeries : LineSeries
{
protected override void UpdateShape()
{
double maximum = ActualDependentRangeAxis.GetPlotAreaCoordinate(
ActualDependentRangeAxis.Range.Maximum).Value;
Func<DataPoint, Point> PointCreator = dataPoint =>
new Point(
ActualIndependentAxis.GetPlotAreaCoordinate(
dataPoint.ActualIndependentValue).Value,
maximum - ActualDependentRangeAxis.GetPlotAreaCoordinate(
dataPoint.ActualDependentValue).Value);
IEnumerable<Point> points = Enumerable.Empty<Point>();
if (CanGraph(maximum))
{
// Original implementation performs ordering here
points = ActiveDataPoints.Select(PointCreator);
}
UpdateShapeFromPoints(points);
}
bool CanGraph(double value)
{
return !double.IsNaN(value) &&
!double.IsNegativeInfinity(value) &&
!double.IsPositiveInfinity(value) &&
!double.IsInfinity(value);
}
}
Result:
It's worth pointing out that, to use #hansmaad's suggestion above, you will need to create a new namespace and point your XAML to this, rather than the assembly.
i.e.
XAML:
xmlns:chart="clr-namespace:MyApplication.UserControls.Charting"
C#:
using System.Windows.Controls.DataVisualization.Charting;
using System.Windows;
namespace MyApplication.UserControls.Charting {
class Chart : System.Windows.Controls.DataVisualization.Charting.Chart {}
class UnorderedLineSeries : LineSeries {
....
}
}
Related
I generated a PageBuilder different UI-Models (TextBlocks, Images) for creating a XAMLLayout.
For this I placed all my Elements on a Canvas and save the complete Canvas to a Xaml-File (With the XamlWriter.Save-Method).
Now I need to generate Charts and serialize them.
With the OxyPlot-Library i used this code for generating the code via runtime.
OxyPlot.Wpf.PlotView pv = new OxyPlot.Wpf.PlotView();
OxyPlot.PlotModel pm = new OxyPlot.PlotModel();
pv.Height = 300;
pv.Width = 500;
pv.Background = Brushes.Red;
pm.Title = "Test";
pm.Series.Add(new OxyPlot.Series.FunctionSeries(Math.Cos, 0, 10, 0.1, "cos(x)"));
pv.Model = pm;
canvas.Children.Add(pv);
For the serialisation I just call my Canvas and serialize the whole objects like this this:
XamlWriter.Save(canvas);
Durring this process I got an exception:
System.InvalidOperationException: "The generic type" System.Collections.Generic.List`1 [OxyPlot.OxyColor] "can not be serialized."
At this point, Generic type only has very limited support in xaml.
XamlWriter cannot serialize a property of a generic list type. You can try the following workaround to fix the issue.
public class OxyPlot
{
public OxyColors OxyColor { get; set; }
}
public class OxyColors : List<OxyColor>
{
}
public class OxyColor
{
}
I would like to cut the extra text and display three dots(...) and when user clicks on the cell, everthing has to be displayed. how to calculate the width of the property grid cell and cut the text. Any help will be grateful.
Pictures are attached for explanation
Instead of this
I would like to achieve this
and it should vary according to the cell size
The property grid does not allow that and you cannot customize it to do so using any official way.
However, here is some sample code that seems to work. It uses a TypeConverter to reduce the value from the grid's size.
Use at your own risk as it relies on PropertyGrid's internal methods and may have an impact on performance, since it requires a refresh on the whole grid on each resize.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// note this may have an impact on performance
propertyGrid1.SizeChanged += (sender, e) => propertyGrid1.Refresh();
var t = new Test();
t.MyStringProperty = "The quick brown fox jumps over the lazy dog";
propertyGrid1.SelectedObject = t;
}
}
public class AutoSizeConverter : TypeConverter
{
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (value == null)
return null;
// small trick to get PropertyGrid control (view) from context
var view = (Control)context.GetService(typeof(IWindowsFormsEditorService));
// bigger trick (hack) to get value column width & font
int width = (int)view.GetType().GetMethod("GetValueWidth").Invoke(view, null);
var font = (Font)view.GetType().GetMethod("GetBoldFont").Invoke(view, null); // or GetBaseFont
// note: the loop is not super elegant and may probably be improved in terms of performance using some of the other TextRenderer overloads
string s = value.ToString();
string ellipsis = s;
do
{
var size = TextRenderer.MeasureText(ellipsis, font);
if (size.Width < width)
return ellipsis;
s = s.Substring(0, s.Length - 1);
ellipsis = s + "...";
}
while (true);
}
}
public class Test
{
// we use a custom type converter
[TypeConverter(typeof(AutoSizeConverter))]
public string MyStringProperty { get; set; }
}
Here is the result (supports resize):
I have just started using gmap.net and I was looking for the functionality of adding labels under the markers. I see there's tooltips but I would like to have a constant label under my marker with a one word description.
I searched for docs or other answers but I cannot find anything which leads me to believe that it is not implemented. If someone can verify this I would appreciate it.
You need to create your own custom marker.
Based on the source of GMapMarker and the derived GMarkerGoogle I came up with this simplified example:
public class GmapMarkerWithLabel : GMapMarker, ISerializable
{
private Font font;
private GMarkerGoogle innerMarker;
public string Caption;
public GmapMarkerWithLabel(PointLatLng p, string caption, GMarkerGoogleType type)
: base(p)
{
font = new Font("Arial", 14);
innerMarker = new GMarkerGoogle(p, type);
Caption = caption;
}
public override void OnRender(Graphics g)
{
if (innerMarker != null)
{
innerMarker.OnRender(g);
}
g.DrawString(Caption, font, Brushes.Black, new PointF(0.0f, innerMarker.Size.Height));
}
public override void Dispose()
{
if(innerMarker != null)
{
innerMarker.Dispose();
innerMarker = null;
}
base.Dispose();
}
#region ISerializable Members
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
}
protected GmapMarkerWithLabel(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
#endregion
}
Usage (assuming a GMap instance named gm):
GMapOverlay markerOverlay = new GMapOverlay("markers");
gm.Overlays.Add(markerOverlay);
var labelMarker = new GmapMarkerWithLabel(new PointLatLng(53.3, 9), "caption text", GMarkerGoogleType.blue);
markerOverlay.Markers.Add(labelMarker)
I'll answer here because this is the first question that pops up when looking to display a text marker for the WPF GMAP.NET library. Displaying a text marker with the WPF version of the library is actually much easier than in WinForms, or at least than the accepted answer.
The GMapMarker in WPF has a Shape property of type UIElement, which means you can provide a System.Windows.Controls.TextBlock object to display a text marker :
Markers.Add(new GMapMarker(new PointLatLng(latitude, longitude))
{
Shape = new System.Windows.Controls.TextBlock(new System.Windows.Documents.Run("Label"))
});
Since the marker displays the top left portion of the shape at the given position, you can play with the GMapMarker.Offset property to adjust the text position according to its dimensions. For instance, if you want the text to be horizontally centered on the marker's position :
var textBlock = new TextBlock(new Run("Label"));
textBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
textBlock.Arrange(new Rect(textBlock.DesiredSize));
Markers.Add(new GMapMarker(new PointLatLng(request.Latitude, request.Longitude))
{
Offset = new Point(-textBlock.ActualWidth / 2, 0),
Shape = textBlock
});
The solution to get the TextBlock's dimensions was quickly taken from this question, so if you need a more accurate way of getting the block's dimensions to play with the offset I suggest you start from there.
I have a WPF application on which the user can paste some data from Word inside a RichTextBox... but if that word data has an image, I need to remove it, how can I accomplish that?
Since the FlowDocument is xml, maybe doing some linq magic could do it, but I don't know how.
There is a tool called WordtoXAML Converter (http://wordtoxaml.codeplex.com). You can use that to convert your Word document contents to XAML, use regular expression matching to identify the images and then strip them out.
The following code will do what you want. While it can be a bit wasteful (it looks through the entire document instead of just the bit that was just pasted), it is the only way to do it, as sometimes the RichTextBox is inaccurate when it indicates the recently painted range:
public class MyTextBox : RichTextBox
{
public MyTextBox()
{
CommandBindings.Add(new CommandBinding(ApplicationCommands.Paste, Paste));
}
protected virtual void Paste(object sender, ExecutedRoutedEventArgs e)
{
Paste();
foreach (var image in FindImages())
{
if (image.SiblingInlines != null)
{
image.SiblingInlines.Remove(image);
}
}
}
IEnumerable<InlineUIContainer> FindImages()
{
var result = new List<InlineUIContainer>();
var blocks = Document.Blocks;
for (TextPointer position = blocks.FirstBlock.ElementStart; position != null && position.CompareTo(blocks.LastBlock.ElementEnd) != 1; position = position.GetNextContextPosition(LogicalDirection.Forward))
{
InlineUIContainer element = position.Parent as InlineUIContainer;
if (element != null && element.Child is Image)
{
result.Add(element);
}
}
return result;
}
}
I'm making a WPF text-editor using TextFormatter. I need to indent some paragraphs, so I'm using the Indent property from the TextParagraphProperties class.
This works great in this scenario:
Regular text without any
indentation.
This paragraph has a uniform
indentation so everything is
ok.
But I also need this:
John: This paragraph has a
diferent indentation
in the first line.
Joe: So I don't know how
to make this happen.
I found the ParagraphIndent and FirstLineInParagraph properties, but I don't know how they works, or if then would be usefull.
Thanks in advance!!
Jose
Jose --
Hopefully this code skeleton will help... I assume that you started from the Advanced Text Formatting project on MSDN, which, sadly is not very advanced. Here is a code fragment you can introduce to MainWindow.Xaml.cs:
TextParagraphProperties textParagraphProperties = new GenericTextParagraphProperties(TextAlignment.Left,
false);
TextRunCache textRunCache = new TextRunCache();
// By default, this is the first line of a paragrph
bool firstLine = true;
while (textStorePosition < _textStore.Length)
{
// Create a textline from the text store using the TextFormatter object.
TextLine myTextLine = formatter.FormatLine(
_textStore,
textStorePosition,
96 * 6,
// ProxyTextParagraphProperties will return a different value for the Indent property,
// depending on whether firstLine is true or not.
new ProxyTextParagraphProperties(textParagraphProperties, firstLine),
lastLineBreak,
textRunCache);
// Draw the formatted text into the drawing context.
Debug.WriteLine("linePosition:" + linePosition);
myTextLine.Draw(dc, linePosition, InvertAxes.None);
// Update the index position in the text store.
textStorePosition += myTextLine.Length;
// Update the line position coordinate for the displayed line.
linePosition.Y += myTextLine.Height;
// Figure out if the next line is the first line of a paragraph
var textRunSpans = myTextLine.GetTextRunSpans();
firstLine = (textRunSpans.Count > 0) && (textRunSpans[textRunSpans.Count - 1].Value is TextEndOfParagraph);
lastLineBreak = myTextLine.GetTextLineBreak();
}
You'll need to create the class ProxyTextParagraphProperties, which descends from TextParagraphProperties. Here's a snip of what I did to test this:
class ProxyTextParagraphProperties : TextParagraphProperties
{
private readonly TextParagraphProperties _paragraphProperties;
private readonly bool _firstLineInParagraph;
public ProxyTextParagraphProperties(TextParagraphProperties textParagraphProperties, bool firstLineInParagraph)
{
_paragraphProperties = textParagraphProperties;
_firstLineInParagraph = firstLineInParagraph;
}
public override FlowDirection FlowDirection
{
get { return _paragraphProperties.FlowDirection; }
}
// implement the same as above for all the other properties...
// But we need to handle this one specially...
public override double Indent
{
get
{
return _firstLineInParagraph ? _paragraphProperties.Indent : 0;
}
}
}