Print Sample for MonoMac - printing

Does anyone know of a MonoMac sample that shows how to implement Print (to a printer)? I haven't been able to find one.

I don't know of one, but the conceptual docs from Apple are relevant, and their sample snippets should be straightforward to port to C#: https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Printing/Printing.html

I created a PrintDocument class a bit like this:
(You'd need to set a proper size and add some drawing in drawrect)
public class PrintDocument:NSView {
NSPrintOperation MyPrinter = null;
static IntPtr selCurrentContext = Selector.GetHandle ("currentContext");
static IntPtr classNSGraphicsContext = Class.GetHandle ("NSGraphicsContext");
public PrintDocument ()
{
MyPrinter=NSPrintOperation.FromView(this);
this.SetFrameSize(new SizeF(600,800));
}
public void Print ()
{
MyPrinter.RunOperation()
}
public override void DrawRect (RectangleF dirtyRect)
{
var context = new NSGraphicsContext (Messaging.IntPtr_objc_msgSend (classNSGraphicsContext, selCurrentContext));
//NSPrintOperation.CurrentOperation
}
}

Related

Convert StackLayout as Image in Xamarin

I'm working on Xmarin Forms(PCL) project, I want to convert the StackLayout to Image / buffer and send it to printer for hard print.
Can anyone suggest how to do it in (Xamarin.Android & Xamarin.iOS).
You can't. Xamarin does not have that kind of feature. You should write a Renderer for your UIComponent.
Fortunately there is an Objective-C iOS implementation, and an Android one as well. You can inspire from them.
Taken from this link, which I have personally used, quite a while back though, the following code will take a screenshot of the entire page.
I ended up modifying the code to only take a screenshot of a specific view on the page and also changed a few other things but this example is what I based it off of, so let me know if you would rather see that code and/or if something below is not working for you.
First you create an interface in your Forms project, IScreenshotManager.cs for example:
public interface IScreenshotManager {
Task<byte[]> CaptureAsync();
}
Now we need to implement our interface in Android, ScreenshotManager.cs for example:
public class ScreenshotManager : IScreenshotManager {
public static Activity Activity { get; set; }
public async System.Threading.Tasks.Task<byte[]> CaptureAsync() {
if(Activity == null) {
throw new Exception("You have to set ScreenshotManager.Activity in your Android project");
}
var view = Activity.Window.DecorView;
view.DrawingCacheEnabled = true;
Bitmap bitmap = view.GetDrawingCache(true);
byte[] bitmapData;
using (var stream = new MemoryStream()) {
bitmap.Compress(Bitmap.CompressFormat.Png, 0, stream);
bitmapData = stream.ToArray();
}
return bitmapData;
}
}
Then set ScreenshotManager.Activity in MainActivity:
public class MainActivity : Xamarin.Forms.Platform.Android.FormsApplicationActivity {
protected override async void OnCreate(Android.OS.Bundle bundle) {
...
ScreenshotManager.Activity = this; //There are better ways to do this but this is what the example from the link suggests
...
}
}
Finally we implement this on iOS, ScreenshotManager.cs:
public class ScreenshotManager : IScreenshotManager {
public async System.Threading.Tasks.Task<byte[]> CaptureAsync() {
var view = UIApplication.SharedApplication.KeyWindow.RootViewController.View;
UIGraphics.BeginImageContext(view.Frame.Size);
view.DrawViewHierarchy(view.Frame, true);
var image = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
using(var imageData = image.AsPNG()) {
var bytes = new byte[imageData.Length];
System.Runtime.InteropServices.Marshal.Copy(imageData.Bytes, bytes, 0, Convert.ToInt32(imageData.Length));
return bytes;
}
}
}

MvvmLight unable to create a controller for key

I am designing a cross platform application architecture using Xamarin iOS and Xamarin Android I decided to go with MvvmLight, it looks descent and is not hiding everything from the MVVM pattern, good and flexible.
While everything started to make sense trying to set it up and learn how to use it, I find myself difficult to understand why I get the following error.
Unable to create a controller for key ChartsPage
The setup.
In a PCL I have my ViewModels. I have a ViewModelLocator setup. I use the mvvmlightlibs Nuget Package.
public class ViewModelLocator
{
public static readonly string SchedulerPageKey = #"SchedulerPage";
public static readonly string ChartsPageKey = #"ChartsPage";
[SuppressMessage("Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "This non-static member is needed for data binding purposes.")]
public SchedulerViewModel Scheduler
{
get
{
return ServiceLocator.Current.GetInstance<SchedulerViewModel>();
}
}
public BizchartsViewModel Bizcharts
{
get
{
return ServiceLocator.Current.GetInstance<BizchartsViewModel>();
}
}
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (ViewModelBase.IsInDesignModeStatic)
{
// Haven't declared something yet
}
else
{
// Haven't declared something yet
}
SimpleIoc.Default.Register<SchedulerViewModel>();
SimpleIoc.Default.Register<BizchartsViewModel>();
}
}
The I have a unified iOS application using universal storyboard with size classes which has an initial UINavigationViewController SchedulerViewController and in the ViewDidLoad method I test the navigation to BizchartsViewController with 3 seconds delay. After 3 seconds I get the exceptions.
In the AppDelegate.
private static ViewModelLocator _locator;
public static ViewModelLocator Locator
{
get
{
if (_locator == null)
{
SimpleIoc.Default.Register<IDialogService, DialogService>();
_locator = new ViewModelLocator();
}
return _locator;
}
}
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
var nav = new NavigationService();
nav.Initialize((UINavigationController)Window.RootViewController);
nav.Configure(ViewModelLocator.ChartsPageKey, typeof(BizchartsViewController));
SimpleIoc.Default.Register<INavigationService>(() => nav);
return true;
}
The SchedulerViewController.
partial class SchedulerViewController : UIViewController
{
public SchedulerViewModel Vm {
get;
private set;
}
public SchedulerViewController (IntPtr handle) : base (handle)
{
Vm = AppDelegate.Locator.Scheduler;
}
public async override void ViewDidLoad ()
{
base.ViewDidLoad ();
await Task.Delay (3000);
Vm.NavigateToCharts ();
}
}
The SchedulerViewModel.
public class SchedulerViewModel : ViewModelBase
{
public void NavigateToCharts()
{
var nav = ServiceLocator.Current.GetInstance<INavigationService>();
nav.NavigateTo(ViewModelLocator.ChartsPageKey);
}
}
I definitely miss a detail somewhere!!!
If you follow carefully the blog post here, it says that with Storyboard you should use the string overload and not the typeof() in nav.Configure(Key, ViewController) and always set the storyboardId and restorationId in the Storyboard ViewController.
Note that because we are using a Storyboard, you must make sure to use
the Configure(string, string) overload, and NOT the Configure(string,
Type) one.

Continuously output from StandardOutput to text box in Visual C# [duplicate]

I have an external dll written in C# and I studied from the assemblies documentation that it writes its debug messages to the Console using Console.WriteLine.
this DLL writes to console during my interaction with the UI of the Application, so i don't make DLL calls directly, but i would capture all console output , so i think i got to intialize in form load , then get that captured text later.
I would like to redirect all the output to a string variable.
I tried Console.SetOut, but its use to redirect to string is not easy.
As it seems like you want to catch the Console output in realtime, I figured out that you might create your own TextWriter implementation that fires an event whenever a Write or WriteLine happens on the Console.
The writer looks like this:
public class ConsoleWriterEventArgs : EventArgs
{
public string Value { get; private set; }
public ConsoleWriterEventArgs(string value)
{
Value = value;
}
}
public class ConsoleWriter : TextWriter
{
public override Encoding Encoding { get { return Encoding.UTF8; } }
public override void Write(string value)
{
if (WriteEvent != null) WriteEvent(this, new ConsoleWriterEventArgs(value));
base.Write(value);
}
public override void WriteLine(string value)
{
if (WriteLineEvent != null) WriteLineEvent(this, new ConsoleWriterEventArgs(value));
base.WriteLine(value);
}
public event EventHandler<ConsoleWriterEventArgs> WriteEvent;
public event EventHandler<ConsoleWriterEventArgs> WriteLineEvent;
}
If it's a WinForm app, you can setup the writer and consume its events in the Program.cs like this:
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
using (var consoleWriter = new ConsoleWriter())
{
consoleWriter.WriteEvent += consoleWriter_WriteEvent;
consoleWriter.WriteLineEvent += consoleWriter_WriteLineEvent;
Console.SetOut(consoleWriter);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
static void consoleWriter_WriteLineEvent(object sender, Program.ConsoleWriterEventArgs e)
{
MessageBox.Show(e.Value, "WriteLine");
}
static void consoleWriter_WriteEvent(object sender, Program.ConsoleWriterEventArgs e)
{
MessageBox.Show(e.Value, "Write");
}
It basically amounts to the following:
var originalConsoleOut = Console.Out; // preserve the original stream
using(var writer = new StringWriter())
{
Console.SetOut(writer);
Console.WriteLine("some stuff"); // or make your DLL calls :)
writer.Flush(); // when you're done, make sure everything is written out
var myString = writer.GetStringBuilder().ToString();
}
Console.SetOut(originalConsoleOut); // restore Console.Out
So in your case you'd set this up before making calls to your third-party DLL.
You can also call SetOut with Console.OpenStandardOutput, this will restore the original output stream:
Console.SetOut(new StreamWriter(Console.OpenStandardOutput()));
Or you can wrap it up in a helper method that takes some code as an argument run it and returns the string that was printed. Notice how we gracefully handle exceptions.
public string RunCodeReturnConsoleOut(Action code)
{
string result;
var originalConsoleOut = Console.Out;
try
{
using (var writer = new StringWriter())
{
Console.SetOut(writer);
code();
writer.Flush();
result = writer.GetStringBuilder().ToString();
}
return result;
}
finally
{
Console.SetOut(originalConsoleOut);
}
}
Using solutions proposed by #Adam Lear and #Carlo V. Dango I created a helper class:
public sealed class RedirectConsole : IDisposable
{
private readonly Action<string> logFunction;
private readonly TextWriter oldOut = Console.Out;
private readonly StringWriter sw = new StringWriter();
public RedirectConsole(Action<string> logFunction)
{
this.logFunction = logFunction;
Console.SetOut(sw);
}
public void Dispose()
{
Console.SetOut(oldOut);
sw.Flush();
logFunction(sw.ToString());
sw.Dispose();
}
}
which can be used in the following way:
public static void MyWrite(string str)
{
// print console output to Log/Socket/File
}
public static void Main()
{
using(var r = new RedirectConsole(MyWrite)) {
Console.WriteLine("Message 1");
Console.WriteLine("Message 2");
}
// After the using section is finished,
// MyWrite will be called once with a string containing all messages,
// which has been written during the using section,
// separated by new line characters
}

Access a Xamarin Component's buttons (specifically the iOS card.io component)

The card.io component (http://components.xamarin.com/view/cardioios) has a fallback screen that has a Cancel and a Done button on them.
Neither of which actually do anything. I assume it is up to me to subscribe to and event, however, there is no event to subscribe to.
Here is the code:
var paymentDelegate = new PaymentViewControllerDelegate();
var paymentViewController = new Card.IO.PaymentViewController(paymentDelegate);
paymentDelegate.OnScanCompleted += (viewController, cardInfo) =>
{
viewController.DismissViewController(true, null);
if (cardInfo == null)
{
}
else
{
new UIAlertView("Card Scanned!", cardInfo.CardNumber, null, "OK", null).Show();
}
};
paymentViewController.AppToken = "app-token";
// Display the card.io interface
base.PresentViewController(paymentViewController, true, () => { });
There is a method on the PaymentViewControllerDelegate, but I can't figure out what to do with it:
public override void UserDidCancel(PaymentViewController paymentViewController);
public override void UserDidProvideCreditCardInfo(CreditCardInfo cardInfo, PaymentViewController paymentViewController);
I guess the problem is that the Component doesn't expose any events for the Fallback View.
You need to subclass PaymentViewControllerDelegate:
public class MyPaymentDelegate : PaymentViewControllerDelegate
{
public MyPaymentDelegate ()
{
}
public override void UserDidCancel (PaymentViewController paymentViewController)
{
// Implement on-cancel logic here...
base.UserDidCancel (paymentViewController);
}
public override void UserDidProvideCreditCardInfo (CreditCardInfo cardInfo, PaymentViewController paymentViewController)
{
// Implement logic for credit card info provided here...
base.UserDidProvideCreditCardInfo (cardInfo, paymentViewController);
}
}
And then provide an instance of this class into the constructor for Card.IO.PaymentViewController:
var paymentDelegate = new MyPaymentDelegate();
var paymentViewController = new Card.IO.PaymentViewController(paymentDelegate);
So, I figured this out by looking at the working sample application and comparing it to what I had done.
All I had to do was widen the scope of the paymentDelegate and paymentViewController variables.
If you look at the sample, you really just need to subscribe to the OnScanCompleted event which is called in both cases of UserDidCancel (where cardInfo will be null), and UserDidProvideCreditCardInfo (where it will not be null).
In fact, this is the code for the binding, so you can see the Event was made as a 'helper' to make it so you didn't have to make your own delegate implementation:
namespace Card.IO
{
public partial class PaymentViewControllerDelegate : BasePaymentViewControllerDelegate
{
public delegate void ScanCompleted(PaymentViewController viewController, CreditCardInfo cardInfo);
public event ScanCompleted OnScanCompleted;
public override void UserDidCancel (PaymentViewController paymentViewController)
{
var evt = OnScanCompleted;
if (evt != null)
evt(paymentViewController, null);
}
public override void UserDidProvideCreditCardInfo (CreditCardInfo cardInfo, PaymentViewController paymentViewController)
{
var evt = OnScanCompleted;
if (evt != null)
evt(paymentViewController, cardInfo);
}
}
}
If you still really want to implement the delegate yourself, subclass BasePaymentViewController instead, however I don't think you really need to make your own subclass of it...
Hopefully that helps!

How can i call dynamic object like a function?

I am studying orchard architecture.i have faced with a strange concept in display management section.
in Partial view page there is a 'function call like' syntax like so Display(Model.Head). that is not a function thought, it is a dynamic object defined in orchard WebViewPage.
I am wondering how to define a dynamic object so that you can call it (and pass it an argument as well) like a function as i mentioned.
thanks in advance.
A lighter weight way to do it without clay would be to subclass the built-in DynamicObject class.
public static dynamic Display;
void Main()
{
Display = new MyCallableObject();
//this is what i was after
Console.Write(Display("bla bla bla"));
}
public class MyCallableObject:DynamicObject
{
public override bool TryInvoke(InvokeBinder binder, object[] args, out Object result)
{
result = string.Format("This is response for {0}",args.FirstOrDefault());
return true;
}
}
I finally found it my self!
all the operations have done with Clay Library behind the scene.i have wrote a sample console app for demonstrating the process.
class Program
{
static void Main(string[] args)
{
Display = ClayActivator.CreateInstance<MyResponser>(new List<IClayBehavior> {new MyFunctionCallBehavior()});
//this is what i was after
Console.Write(Display("bla bla bla"));
}
public static dynamic Display;
}
public class MyFunctionCallBehavior : IClayBehavior
{
public object InvokeMember(Func<object> proceed, object self, string name, INamedEnumerable<object> args)
{
return ((MyResponser)self).ResponseForRequest(args.FirstOrDefault().ToString());
}
}
public class MyResponser
{
public string ResponseForRequest(string param)
{
return string.Format("This is response for {0}",param);
}
}

Resources