Plotmodel to XPS via OxyPlot C# - c#

I'm currently facing a problem with printing a Plotmodel to an XPS-File.
What I have so far:
/// <summary>
/// Plotmodel to XPS-File
/// </summary>
/// <param name="model">The model</param>
/// <param name="fileName">The fileName</param>
/// <param name="width">Width of the model</param>
/// <param name="height">Height of the model</param>
public void Export(PlotModel model, string fileName, double width, double height)
{
try
{
using (Package xpsPackage = Package.Open(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
using (var doc = new XpsDocument(xpsPackage))
{
var g = new Grid();
var p = new OxyPlot.Wpf.Plot { Model = model }; //Problem?
g.Children.Add(p);
var size = new Size(width, height);
g.Measure(size);
g.Arrange(new Rect(size));
g.UpdateLayout();
if (xpsdw == null) //XpsDocumentWriter xpsdw
xpsdw = XpsDocument.CreateXpsDocumentWriter(doc);
}
if (xpsdw != null)
{
xpsdw.Write(g);
}
}
}
}
This Code works fine (once), but the Problem is: No matter how often you use this method, you will always have just one Page with data. So if you want to print a second Plotmodel into the XPS-File the old one is deleted and you can only see the new one.
So the Question is:
Do you have an idea, how to append the new Plotmodel to the old XPS-File without overwriting it?
I also tried to use:
XpsExporter.Export(model, fileName, width, height);
instead of my function, but this didn't worked either.

If you know in advance that you will be writing multiple plots to a single file, you should look into VisualsToXpsDocument.
If you truly must append additional pages to an existing document on disk, it will be more difficult. You will need to dig down through the existing document to get to a FixedDocument (a child of the FixedDocumentSequence). Once you have the FixedDocument, you can add a new PageContent object to it. There is an example near the bottom of this thread.

Related

How can you store a Control in a class and reuse it in a binding?

I am trying to reuse NumberBoxes for a GridView because having the NumberBoxes embedded directly in the GridView data template causes undesirable behavior, while reusing them does not. The problem is that I keep getting exceptions. They say "No installed components were detected" on the following line (templateRoot.FindName("NumberBox") as GridViewItem).Content = item.NumberBox; in this context
/// <summary>
/// The callback for updating a container in the GridView named CardGridView.
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
private void UpdateGridViewContainer(ListViewBase sender, ContainerContentChangingEventArgs args)
{
if (args.Phase == 1)
{
Grid templateRoot = args.ItemContainer.ContentTemplateRoot as Grid;
CardItem item = args.Item as CardItem;
(templateRoot.FindName("NumberBox") as GridViewItem).Content = item.NumberBox;
TypedEventHandler<NumberBox, NumberBoxValueChangedEventArgs> handler =
(box, args) =>
{
if (!double.IsNaN(args.NewValue))
{
_viewModel.ChangeCount(args, item);
}
};
item.SetHandler(handler);
}
}
The exception is thrown when the Page that contains the GridView is left and renavigated to. I have tried nulling out the NumberBoxes when the page is left, but that did not work. Well, it appeared to before the issue cropped up again.
This is the code that nulls out the NumberBoxes
/// <summary>
/// Creates new NumberBoxes for when this Page is loaded again.
/// </summary>
private void ResetNumberBoxes()
{
foreach (CardItem card in CardGridView.Items.Cast<CardItem>())
{
card.ResetNumberBox();
}
CardGridView.ItemsSource = null;
CardGridView.Items.Clear();
}
ResetNumberBox is just setting the NumberBox to null and assigning a new one.
The exception details
System.Runtime.InteropServices.COMException
HResult=0x800F1000
Message=No installed components were detected. (0x800F1000)
Source=WinRT.Runtime
StackTrace:
at WinRT.ExceptionHelpers.<ThrowExceptionForHR>g__Throw|20_0(Int32 hr)
at ABI.Microsoft.UI.Xaml.Controls.IContentControlMethods.set_Content(IObjectReference _obj, Object value)
An update. I have removed the GridViewItem control from the DataTemplate and tried doing the following with the same result
CardItem item = args.Item as CardItem;
Grid.SetColumn(item.NumberBox, 1);
item.NumberBox.HorizontalAlignment = HorizontalAlignment.Center;
item.NumberBox.VerticalAlignment = VerticalAlignment.Center;
(templateRoot.FindName("GridViewTemplate") as Grid).Children.Add(item.NumberBox);
I also examined a heap dump right before the line that throws, and there was only one instance of the Grid, and the NumberBox had a parent of null.

Interactive Data display in c#

I have some csv files that I try to read and then divide them in two columns or list and plot them in a mathematical chart.
The csv files contains two columns, one for voltage and one for time. I read the csv files and use Interactive Data display
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Windows;
using System.Windows.Controls;
namespace TWord.Pages
{
/// <summary>
/// Interaction logic for Pico.xaml
/// </summary>
public partial class Pico : Page
{
/// <summary>
/// Members
/// </summary>
int numEvent;
StreamReader myCSVStream;
int currentSlide;
ListOfList<double> AllEventsList;
/// <summary>
/// Constructor
/// </summary>
public Pico()
{
InitializeComponent();
}
#region Button Event
/// <summary>
/// Implement the button function to read the csv files.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnCSV_Browser_Click(object sender, RoutedEventArgs e)
{
// Creates a null stream
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Multiselect = openFileDialog.RestoreDirectory = true;
// Initial directory to open to
openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
// only open the csv files
openFileDialog.Filter = "csv files (*.csv)|*.csv|All files (*.*)|*.*";
// Applying filter index
openFileDialog.FilterIndex = 2;
// Create a new instance of list of lists and
// run the ReadCSV for each of files.
if (openFileDialog.ShowDialog() == true)
{
// Names of the files imported
string[] filePath = openFileDialog.FileNames;
// Path of the file
numEvent = openFileDialog.FileNames.Length;
AllEventsList = new ListOfList<double>();
foreach (var address in filePath)
{
ReadCSV(address);
}
}
// only if thr browser had done the work
//if (AllEventsList != null)
// DrawPlot(0);
}
#endregion
#region Help Functions
/// <summary>
/// Help function to make graphs and reading the csv files.
/// </summary>
private void ReadCSV(string s)
{
string line;
// new stream to read each line
myCSVStream = new StreamReader(s);
// one list for voltage
List<double> voltage = new List<double>();
// one list for time
List<double> time = new List<double>();
// reading whole csv file and split it into two columns
while ((line = myCSVStream.ReadLine()) != null)
{
try
{
string[] parm = line.Trim().Split(',');
voltage.Add(double.Parse(parm[0], CultureInfo.InvariantCulture));
time.Add(double.Parse(parm[1], CultureInfo.InvariantCulture));
}
catch { }
}
// add it to the list of lists.
AllEventsList.Add(voltage);
AllEventsList.Add(time);
// Draw the first plot
DrawPlot(0);
}
#endregion
#region
/// <summary>
/// Drawing the plot for the CSVs
/// </summary>
private void DrawPlot(int i)
{
// Array for Voltage
double[] voltage = AllEventsList[2 * i].ToArray();
// Array for time
double[] time = AllEventsList[2 * i + 1].ToArray();
//plot to the linegraph
linegraph.Plot(time,voltage,);
}
#endregion
}
}
The XAML file to this is according to :
<GroupBox Grid.Row="1" Grid.Column="0" Header="Sampled points" Style="{StaticResource GroupboxStyle}" FontFamily="{StaticResource LatoThin}" Foreground="{StaticResource TercoTextBrush}">
<d3:Chart BottomTitle="Time" LeftTitle="voltage" Margin="-10" Style="{DynamicResource ChartStyle}">
<d3:LineGraph x:Name="linegraph" Description="Simple linegraph" Stroke="Blue" StrokeThickness="2" Margin="-19,0,0,-23"/>
</d3:Chart>
</GroupBox>
The result is that the line itself sticks out of the graph grid. as image below: Ive been sitting here and tried to modify the style of the graph with no luck. Anyone had this problem? The reason I use Interactive Data display is that it is very simple to use. Just needs two arrays and you are done. If you have any better suggestions that is Free of charge I would be happy to know about it. but not Oxyplot . I couldn't make it work
Your margin for your LineGraph XAML markup is shifting the line.
Margin is specified as:
<object Margin="left,top,right,bottom"/>
So a margin of -19,0,0,-23 specifies a shift to a xaml element 19 units to the left and 23 units down. Which is what you are seeing.
Change:
<d3:LineGraph x:Name="linegraph" Margin="-19,0,0,-23" Description="Simple linegraph" Stroke="Blue" StrokeThickness="2" />
To:
<d3:LineGraph x:Name="linegraph" Margin="0" Description="Simple linegraph" Stroke="Blue" StrokeThickness="2" />

Does Bringtofront() go before or after ResumeLayout? Does it matter?

So I've been digging into the whole SuspendLayout()/ResumeLayout() logic for a while now and I've been trying to implement it in the most efficient manner. One question I'm unable to find an answer for is that of which I've asked in the title : Does the BringToFront() method go before or after you call ResumeLayout()? Does it matter? My initial thought process is no, it doesn't matter, because it's only changing the z-index of the control and not effecting the control's layout, but I just want to be sure.
Here's block of code from my project where my question comes into play:
Note:This project runs on a Motorola MC65 mobile device and uses .net compact 3.5 framework
/// <summary>
/// Initializes the <see cref="VerifyReplacementPanel"/> class
/// </summary>
/// <param name="hostControl">The panel this control is being added to</param>
/// <param name="original">The product being replaced</param>
/// <param name="replacement">The product replacing with</param>
/// <param name="logHelper">The log helper interface</param>
public VerifyReplacementPanel(Control hostControl, ProductModel original, ProductModel replacement, ILogHelper logHelper)
{
hostControl.SuspendLayout();
SuspendLayout();
HostControl = hostControl;
Product = original;
Replacement = replacement;
_logHelper = logHelper;
Size = Size.FullScreen();
// original product panel
var panOrig = new blkPan(472, 75) { Location = new Point(4, 147), BackColor = Color.White };
var originalProductPanel = new ProductPanelArrayModel(panOrig, _logHelper);
originalProductPanel.AddPanelWithPic(original);
Controls.Add(panOrig);
// replacement product panel
var panRepl = new blkPan(472, 75) { Location = new Point(4, panOrig.B + 100), BackColor = Color.White };
var replacementProductPanel = new ProductPanelArrayModel(panRepl, _logHelper);
replacementProductPanel.AddPanelWithPic(replacement);
Controls.Add(panRepl);
// no button
var btnNo = new PushButton("No", ObjectName, true) { Location = new Point(38, Bottom - 93 - 36) };
btnNo.Click += btnNo_Click;
Controls.Add(btnNo);
_btnNoTop = btnNo.Top;
// yes button
var btnYes = new PushButton("Yes", ObjectName, true) { Location = new Point(259, btnNo.Top) };
btnYes.Click += btnYes_Click;
Controls.Add(btnYes);
ResumeLayout(false);
HostControl.Controls.Add(this);
BringToFront();
HostControl.ResumeLayout();
}
My question is interested in this section :
ResumeLayout(false);
HostControl.Controls.Add(this);
BringToFront();
HostControl.ResumeLayout();
Also, am I even using it correctly? Thank you for your time.

Change background of the thumb of Trackbar

Is any way to change the background of the thumb of Trackbar? I use C# winform.
Only the background of the Trackbar can be changed, so how can I change or set something in the thumb?
Any answer appreciated.
I saw the project:
http://www.codeproject.com/Articles/7974/A-variation-on-the-default-TrackBar
And add the Picture of it to let user choose:
/// <summary>
/// Set Image of Trackbar's thumb
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
[Description("Set the picture of the thumb")]
[Category("Image")]
public Image Picture
{
set
{
myPic = value;
}
get { return myPic; }
}
And use TextureBrush to let the picture People shoose be an ImageBrush:
TextureBrush newBrush = new TextureBrush(myPic);
if (myPic != null)
{
g.FillRegion(newBrush, new Region(PaintPath));
newBrush.Dispose();
}
else
{
g.FillRegion(bgBrush, new Region(PaintPath));
bgBrush.Dispose();
}
There is only one problem that the imagebrush is tile style,
if I let it not a tile style, it may resolve my questrion.

How can I make a WPF Image disableable?

I need an Image that is grayed out when disabled (IsEnabled=False). A grayed out version of the image can be produced by reading the BitmapImage into a FormatConvertedBitmap which is shown here.
I have been able to get this working with a UserControl but now I would like the same behavior in a specialized Image class for more flexibility. I don't care if this is implemented in XAML, code-behind or both, but it needs to be a subclass of Image.
The usage could be:
<DisableableImage Source="Images/image1.png" />
<DisableableImage Source="Images/image1.png" IsEnabled="False" />
<!-- Since IsEnabled is inherited down the tree,
the image will be grayed out like the rest of the button -->
<Button IsEnabled="False">
<StackPanel Orientation="Horizontal">
<TextBlock>OK</TextBlock>
<DisableableImage Source="Images/ok.png" />
</StackPanel>
</Button>
Have a look at this link
EDIT:
Or this one (all you need is the AutoGreyableImage class)
I made a little comparison based on the following solutions.
The approaches in the link provided by the OP
The links provided by Thomas Levesque
AutoDisabledImage
AutoGreyableImage
Greyscale Effect
Since I already had a licens for the Infragistics Net Advantage for WPF it was easy to try it out
Here is the result
So the best approach depends on what results you are after. As for me, I think the result produced by AutoDisabledImage from Infragistics is too bright, AutoGreyableImage does a pretty good job (Identical result to Approach 1 (OP link)) and GreyscaleEffect produces the best result.
if you use this a lot consider creating a custom Effect introduced with .NET 3.5 SP1 (not bitmapeffect) to render such an operation on your GPU. this effect can then be easily controlled by triggers.
More complete version of the AutoGreyableImage by Thomas Lebrun. For anyone interested, I started using Thomas Lebruns class and ran into a couple of nullreference exceptions, as well as finding out that an image would not be disabled if the isEnabled property was set first and the source set after.
So here's the class that finally did the trick for me. À propos, you can of course add the matter of opacity into this, but I decided to leave that up to the xaml around the image.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using System.Windows.Media;
namespace MyDisabledImages
{
/// <summary>
/// Class used to have an image that is able to be gray when the control is not enabled.
/// Based on the version by Thomas LEBRUN (http://blogs.developpeur.org/tom)
/// </summary>
public class AutoGreyableImage : Image
{
/// <summary>
/// Initializes a new instance of the <see cref="AutoGreyableImage"/> class.
/// </summary>
static AutoGreyableImage()
{
// Override the metadata of the IsEnabled and Source property.
IsEnabledProperty.OverrideMetadata(typeof(AutoGreyableImage), new FrameworkPropertyMetadata(true, new PropertyChangedCallback(OnAutoGreyScaleImageIsEnabledPropertyChanged)));
SourceProperty.OverrideMetadata(typeof(AutoGreyableImage), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnAutoGreyScaleImageSourcePropertyChanged)));
}
protected static AutoGreyableImage GetImageWithSource(DependencyObject source)
{
var image = source as AutoGreyableImage;
if (image == null)
return null;
if (image.Source == null)
return null;
return image;
}
/// <summary>
/// Called when [auto grey scale image source property changed].
/// </summary>
/// <param name="source">The source.</param>
/// <param name="args">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
protected static void OnAutoGreyScaleImageSourcePropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs ars)
{
AutoGreyableImage image = GetImageWithSource(source);
if (image != null)
ApplyGreyScaleImage(image, image.IsEnabled);
}
/// <summary>
/// Called when [auto grey scale image is enabled property changed].
/// </summary>
/// <param name="source">The source.</param>
/// <param name="args">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
protected static void OnAutoGreyScaleImageIsEnabledPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs args)
{
AutoGreyableImage image = GetImageWithSource(source);
if (image != null)
{
var isEnabled = Convert.ToBoolean(args.NewValue);
ApplyGreyScaleImage(image, isEnabled);
}
}
protected static void ApplyGreyScaleImage(AutoGreyableImage autoGreyScaleImg, Boolean isEnabled)
{
try
{
if (!isEnabled)
{
BitmapSource bitmapImage = null;
if (autoGreyScaleImg.Source is FormatConvertedBitmap)
{
// Already grey !
return;
}
else if (autoGreyScaleImg.Source is BitmapSource)
{
bitmapImage = (BitmapSource)autoGreyScaleImg.Source;
}
else // trying string
{
bitmapImage = new BitmapImage(new Uri(autoGreyScaleImg.Source.ToString()));
}
FormatConvertedBitmap conv = new FormatConvertedBitmap(bitmapImage, PixelFormats.Gray32Float, null, 0);
autoGreyScaleImg.Source = conv;
// Create Opacity Mask for greyscale image as FormatConvertedBitmap does not keep transparency info
autoGreyScaleImg.OpacityMask = new ImageBrush(((FormatConvertedBitmap)autoGreyScaleImg.Source).Source); //equivalent to new ImageBrush(bitmapImage)
}
else
{
if (autoGreyScaleImg.Source is FormatConvertedBitmap)
{
autoGreyScaleImg.Source = ((FormatConvertedBitmap)autoGreyScaleImg.Source).Source;
}
else if (autoGreyScaleImg.Source is BitmapSource)
{
// Should be full color already.
return;
}
// Reset the Opcity Mask
autoGreyScaleImg.OpacityMask = null;
}
}
catch (Exception)
{
// nothin'
}
}
}
}
Create a DisableableImage class that is a typical WPF control. Inside, place two elements: the image, and a rectangle that appears only when the control is disabled. The rectangle should be the same width and height as the image, and it should overlay the image. With a color of gray and an alpha of somewhere around 40%, you should get an effect similar to actually graying out the image -- without all the effort to actually modify the image itself.

Categories

Resources