printing with silverlight the same image multiple time - silverlight

I have an image an a textbox. the user enters into the textbox the number of copies (N) and clicks print. The printer prints the photo N times (3 photos per page, one under the other).
Hiw would you do something like that? Do I need to first generate a silverlight page?

Silverlight has a really simple to use Printing API. I have recently been using it and learnt how to do so using the tutorial Melodatron listed, and this one over at the Visiblox site. This is specific to their charting library but I still found it very useful.
I am assuming that you only have 1 image to print at a time here, let me know if you have more. First, you need to set up a grid or something similar to put your photos in. You will need N number of rows in this grid. You'll have to do this in code behind as you have a certain number of rows you'd like to create, but this can easily be achieved by something like this:
Grid grid = new Grid();
// Set the column and row definitions
for (int i = 0; i < Number of rows; i++)
{
grid.RowDefinitions.Add(new RowDefinition());
}
That should set up your grid that you need. After you have the grid, you need to populate it with the images that you have. This is pretty straightforward, the only issue will be that your image can't be used multiple times - i.e. the image that you already have can only appear on the grid once. You will have to duplicate it in order to place it on the grid multiple times. I'm not sure how you are creating your images, but you could possibly create a new image based on the source path of the existing image? There is a thread on how to do this here. You'll need to give more details if you need help with that.
// Set the column and row definitions
for (int i = 0; i < Number of rows; i++)
{
// Duplicate your existing image here.
Image image = new Image();
grid.Children.Add(image);
Grid.SetRow(image, i);
}
All of the code above should be in this method:
private void printDocument_PrintPage(object sender, PrintPageEventArgs e)
{
//Code from above...
e.PageVisual = grid;
}
In the button event handler where you wish to print, do this:
private void Button_Click(object sender, RoutedEventArgs e)
{
PrintDocument printDocument = new PrintDocument();
printDocument.PrintPage += new EventHandler<PrintPageEventArgs>(printDocument_PrintPage);
printDocument.Print("TITLE");
}
Hope this helps!

There's a pretty good tutorial (link below) with an example and source code on advanced printing techniques in Silverlight.
You will need to create the layout as a custom control, which should not be so difficult, but you won't need to display it.
http://www.silverlightshow.net/items/Advanced-printing-in-Silverlight-4.aspx
Hopefully this gets you started in the right direction.

Related

Printing in Silverlight cuts off some portion

How do I provide a print option on my silverlight application. I am able to print using the PrintDocument class but it cuts of the edges.
Is there a way to shrink the view to fit in a print paper. Thanks for any help.
I am using the below code:
PrintDocument document = new PrintDocument();
document.PrintPage += (s, args) =>
{
args.PageVisual = this.LayoutRoot;
};
document.Print("Silverlight Print Application Demo");
There are two conceptually different tasks here:
Printing an element as rendered in the ui at some point and
Render an element exclusively for printing.
Since you're complaining about the cutting off of edges, I assume you want to do the latter. For that, I wouldn't add the current control's layout root, which I suspect you're doing. Add something that is not yet added to the visual tree, or remove it from its parent before printing.
If you have to remove it first for some reason (perhaps because the user needs to interact with it first), then store the element in a variable printedPage that you can re-add to the visual tree on the PrintDocument.EndPrint event.
For the main event handler use something like this:
void HandlePrintPage(object sender, PrintPageEventArgs e)
{
var panel = new Grid();
// get an element to print that is not attached to the visual tree
printedPage = GetDetachedPageToPrint();
panel.Children.Add(printedPage.ReportPage);
// we wrap it in a Viewbox to make it full-page
var viewbox = new Viewbox() { Child = panel };
// we need to have a measure pass
viewbox.Measure(e.PrintableArea);
e.PageVisual = viewbox;
// for more pages, we would need to be more careful
//with parent detachments
e.HasMorePages = false;
}
I had the same problem a couple of months ago and tried several solutions.
I`ve already answered this question in another post. Please check out this:
https://stackoverflow.com/a/20896774/1141477
It converts the framework element into images and fit it inside a rectangle, which is from the same size as the printableArea. It worked well to me.
Hope it helps!

Changing the bitmap shown in a PictureBox for different TrackBar values

I'm trying to use a TrackBar to control the image that is show in a PictureBox. There are 4 values for the TrackBar (0-4) and four images. The TrackBar's default value is 0 and currently I have set the Background image property to the image I would like to represent the 0 value (not sure if this is even the correct way to start).
so far i'v tried:
private void TrackBar1_Scroll(object sender, EventArgs e)
{
if (TrackBar1.Value == 1)
{
PictureBox1.BackgroundImage = ((System.Drawing.Image)(Properties.Resources.Image2))
}
}
but this hasn't worked. I've got all the relevant images in the resources file all saved as bitmaps...
Any help would be greatly appreciated, still learning the ropes
Thanks
Harry
Not to worry I solved it myself, the code I had used worked, I'd just forgotten to update the scroll event property to the TrackBar1_Scroll Event

in VC++2008 Form Application which component is used for display many lines text?

I am writing a socket client *Form Application*. i want to display message we sent and received in an area to monitor the communication. is the ListBox a right component for this purpose?
EDIT:
Why the ListBox display is not line by line but only showing at the end? the TextBox is showing new text each time.
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
this->listBox1->MultiColumn = true;
for(int i = 0; i <10; i++)
{
this->textBox1->AppendText(String::Format( "Item {0}", i ));
this->listBox1->BeginUpdate();
this->listBox1->Items->Add( String::Format( "Item {0}", i ));
listBox1->EndUpdate();
Sleep(500);
}
}
I was thinking use label but cannot find a scrolling control with it.
This is the first time I use Form Application. Please be patient.
I always use a TextBox control, set it to multiline and prepend, rather than append the new lines. This way the most recent text is always on top and you don't have to worry about scrolling. You can do the same with a label control, too, but you lose the ability to scroll down.
If course, depending on how long-running this is, you may need to clean up instead of just keeping all the text indefinitely. You'll run into memory issues if you do keep all of the text indefinitely.

Winforms Usercontrol: Perfomance issues when creating and adding to parent

I have built a UserControl for display a list of other UserControls which themselves are bound to individual data objects. The link below shows an example implementation of this control.
Each of the individual user rows is its own UserControl/XtraUserControl, laid out in a FlowLayoutPanel.
The problem I have is with perfomance, to populate the list above takes around 500ms (excluding any data loading) - this is a combination of creating each control and then adding them to the FlowLayoutPanel using the AddRange(controls[]) method.
Does anyone know any way I can improve perfomance here? Do I have to manually paint the items instead of using User Controls?
Thanks in advance.
EDIT: I've added my own response below showing the solution I have stuck with for now.
Whether manually painting would help is a guess. Even if it were right (which I doubt) it's better not to guess.
I've seen this kind of issue before, and chances are there's a lot of stuff that goes on in the binding.
The way I've solved the problem is with this approach, but it's definitely "out there" in terms of programmer acceptance.
I gues you are using devexpress controls because you mention XtraUserControl. If so, why don't use an XtraGrid?You can add images column and button columns, and I think you'll get better performance and simpler/less code
First of all, try use pair SuspendLayout()/ResumeLayout(), then it has sense to stop painting at all by hiding the container control until all child usercontrols added.
Anyway, placing lots of child controls to a container is not a good idea.
You can have the same result by using highly customized grid or by custom painting (which is preferable).
Good luck!
I had a brainwave for another solution which I'm not quite sure is appropriate. I would really appreciate any feedback on this.
Two rationales led to this solution:
Firstly I wanted the flexibility of creating rows like any other control.
Secondly the lists that would use this approach only intend to display brief chunks of data, never more than say 20 items - for anything larger, ListViews are used.
So anyway, what I decided to do was cache a set number of the Panels (I've referred to the custom controls or rows as Panels throughout the code) and to build up this cache as the control is created. When populating the control with BusinessObjects, the existing cached Panels are displayed with their bound BusinessObject. You can see how this works exactly from the code below, so there is no need for a in-depth description.
The fact of the matter is that I've managed to reduce the data population time (after the initial cache setup of around 180ms for 10 Panels) from 500ms to 150ms for the list shown in the image above.
private int cacheSize = 10;
private List<P> cachedPanels = new List<P>(10);
private void InitItems()
{
this.contentPanel.SuspendLayout();
// Create the cached panels from the default cache value.
for (int i = 0; i < cacheSize; i++)
cachedPanels.Add(new P() { Margin = new Padding(0), Visible = false });
this.contentPanel.Controls.AddRange(cachedPanels.ToArray());
this.contentPanel.ResumeLayout(true);
}
private void PopulateListFromCache()
{
this.contentPanel.SuspendLayout();
// Iterate against both BusinessObjects and Panels to ensure that nothing is missed, for
// instance, where there are too many panels, the rest are hidden, and too many Business
// Objects, then more Panels are created.
for (int i = 0; i < this.businessObjects.Count || i < this.cachedPanels.Count; i++)
{
if (i >= this.cachedPanels.Count)
{
// Here, we have more BusinessObjects than Panels, thus we must create
// and assign a new panel.
this.cachedPanels.Add(new P() { Margin = new Padding(0) });
this.cachedPanels[i].Item = this.businessObjects[i];
this.contentPanel.Controls.Add(this.cachedPanels[i]);
}
else if (i >= this.businessObjects.Count)
{
// Here, we still have Panels cached but have run out of BusinessObjects,
// let's just hide them and clear their bindings.
this.cachedPanels[i].Item = default(T);
this.cachedPanels[i].Visible = false;
}
else
{
// Here, we have both BusinessObjects and Panels to put them in, so just
// update the binding and ensure the Panel is visible.
this.cachedPanels[i].Item = this.businessObjects[i];
this.cachedPanels[i].Visible = true;
}
}
this.contentPanel.ResumeLayout(true);
}
Obviously, more optimizations can be made, such as un-caching Panels after a certain amount of time of not being used etc. Also, I'm not entirely sure if keeping these controls - which are rather simple - in a cache will affect memory usage much.
If anyone can think of any other pointers then please, be my guest. Oh, and if you got this far, then thank you for reading this.

How can I change the way InkCanvas draws?

I've searched for examples for this, but the ones I've ran across seem to focus on simpler stuff like setting the InkCanvas DefaultDrawingAttributes such as Width, Height, Color etc. Doesn't seem like there's a lot of material for this.
For example, if I hold down the mouse button I can see it drawing lines. What if I want to draw ellipses instead of lines, or draw ellipses around sampled points between the start and end of the line?
I know I can get new points with the StrokeCollected event, but beyond that I have no idea where to go. This guy seemed like he got msdn's code working, but I couldn't do it. I only know how to build the interface using XAML, and there doesn't seem to be a sample either.
edit
Created a StrokeCollection class variable called thisIsNotNice, initialized in the constructor and did this:
private void InkCanvas_StrokeCollected(object sender, InkCanvasStrokeCollectedEventArgs e)
{
myInkCanvas.Strokes = thisIsNotNice;
foreach (StylusPoint p in e.Stroke.StylusPoints)
{
StylusPointCollection spc = new StylusPointCollection();
spc.Add(p);
Stroke s = new Stroke(spc);
s.DrawingAttributes.Height = 3;
s.DrawingAttributes.Width = 3;
thisIsNotNice.Add(s);
}
e.Handled = true;
}
But it doesn't work as it should. The ellipses are drawn, but the lines drawn by the mouse are still there. Also, for some reason, the first time it works as it should, drawing just the ellipses, but afterward it draws both the ellipses and the lines. But, if I do this instead:
private void InkCanvas_StrokeCollected(object sender, InkCanvasStrokeCollectedEventArgs e)
{
myInkCanvas.Strokes = new System.Windows.Ink.StrokeCollection();
e.Handled = true;
}
The lines aren't kept on the screen. So, I don't understand why they aren't being erased in the above code.
If I do this:
private void InkCanvas_StrokeCollected(object sender, InkCanvasStrokeCollectedEventArgs e)
{
foreach (Stroke s in myInkCanvas.Strokes)
System.Diagnostics.Trace.WriteLine(s);
e.Handled = true;
}
I can also see that the canvas contains the line strokes.
While erasing the strokes after they have been added to the collection is far from ideal, it at least does what I want. I could set up the line color to be the same of the background, but then I wouldn't be able to retrieve just the ellipses. I could copy them to a separate collection too, but that's just awful.
It sounds like you want to customize the way strokes appear on your inkCanvas. There are two separate things to consider here:
1) The way they look as the ink flows off the pen, before it is lifted (the DynamicRenderer, who runs on another thread to ensure that ink is always fast, is responsible for this. It sounds like you're happy with your solution to this already.
2) The way the eventual stroke sitting on the canvas looks. To customize this you might try subclassing Stroke, overriding:
protected override void DrawCore(DrawingContext drawingContext, DrawingAttributes drawingAttributes);
Each time you get a strokeCollected (and here's the same horrible thing you were worried about but there you go), you remove the incoming stroke from the canvas and replace it with your custom implementation, stealing the stroke data from the incoming one.
Your implementation of DrawCore would look something like (pseudocode):
foreach(sp in this.StylusPoints)
drawingContext.DrawEllipse(RADIUS, sp.X, sp.Y)
And so as not to get the lines that normally happen you would not call base.DrawCore(context,attributes) at any point.

Resources