Add and bind UIView on External Monitor using MvvmCross - mvvm

I'm attempting to Display an UIView on an external monitor in iOS if one is detected. I am able to detected and display a simple UIView using the following code...
public void CheckForExternalDisplay()
{
if (UIScreen.Screens.Length > 1)
{
Mvx.Trace(MvxTraceLevel.Diagnostic, "Multiple screens found");
var externalScreen = UIScreen.Screens[1];
var rect = new RectangleF(new PointF(0, 0), externalScreen.AvailableModes.Max(m => m).Size);
var window = new UIWindow(rect)
{
Screen = UIScreen.Screens[1],
ClipsToBounds = true,
Hidden = false
};
var presenterView = new PresenterView(rect);
window.AddSubview(presenterView);
}
}
This UIView is Very Simple. It contains a UILabel and a RadialProgress View. Most of the heavy lifting to determine what the values should be are already being done on another viewmodel that is updating a view attached to a screen on the phone. I have tried several techniques to try and get the UIView on the external display to update.
Using MvxMessenger. - I tried passing a message to both a new ViewModel and to the View itself. The new ViewModel received the message only after I created a new instance from the publishing viewmodel. However, I could never intercept messages directly from the view...
Delay binding and regular fluent binding where the bound viewmodel properties are simply updated from another viewmodel.
Attempted to bind this View with a viewmodel already associated with another view.
Wishing in one hand, and crapping in the other... Guess which one filled up first ;)
It's almost as if the UIview (below), isn't being registered/associated with a viewmodel. I'm sure I'm missing something somewhere. As always, I appreciate the help!
public sealed class PresenterView
: MvxView
{
private readonly RadialProgressView _progressView;
private readonly MvxSubscriptionToken _token;
private IMvxMessenger _messenger;
private UILabel _displayLabel;
public PresenterView(RectangleF frame)
: base(frame)
{
Frame = frame;
_messenger = Mvx.Resolve<IMvxMessenger>();
_token = _messenger.Subscribe<DisplayMessage>(OnDisplayMessageReceived);
_displayLabel = new UILabel
{
AdjustsFontSizeToFitWidth = true,
Lines = 1,
LineBreakMode = UILineBreakMode.TailTruncation,
Text = "This is a workout",
Font = UIFont.FromName("rayando", 96f),
BackgroundColor = UIColor.Clear,
PreferredMaxLayoutWidth = Frame.Width - 10,
Frame = new RectangleF(0, 0, Frame.Width - 10, frame.Height / 7),
TextColor = UIColor.White,
TextAlignment = UITextAlignment.Center,
AutoresizingMask = UIViewAutoresizing.All
};
AddSubview(_displayLabel);
_progressView = new RadialProgressView
{
Center = new PointF(Center.X, Center.Y),
MinValue = 0f,
};
AddSubview(_progressView);
this.DelayBind(() =>
{
MvxFluentBindingDescriptionSet<PresenterView, PresenterViewModel> set =
this.CreateBindingSet<PresenterView, PresenterViewModel>();
set.Bind(_progressView).For(pv => pv.Value).To(vm => vm.ClockValue);
set.Bind(_progressView).For(pv => pv.MaxValue).To(vm => vm.MaxProgress);
set.Bind(_workoutLabel).To(vm => vm.DisplayText);
set.Apply();
});
}
private void OnDisplayMessageReceived(DisplayMessage obj)
{
_workoutLabel.Text = obj.Message;
}
}
I do realize that I have included both solutions here. I did try each of them independently.

From the code you've posted, I can't see anywhere you are actually setting the data context for your view.
In 'normal mvvmcross' either:
an MvxViewController creates its own DataContext (ViewModel) using its show request in viewDidLoad
some other app code sets an MvxView's DataContext based on app- specific logic - see n=32 in http://mvvmcross.wordpress.com as an example
In your code, i can't currently see where you set this - so try setting view.DataContext somewhere.

Related

How do I know when to add a new page?

So I'm generating tables with cells based on some data that I get from a database.
And my question is simple, how do I know when to create a new page? I would have to calculate the height of each table and make sure that they're within the size of the page, and if the next table isn't, well then create a new page and add it to that one.
The issue is I'm not sure if this is the right approach. Is this how you would do it? And if so, how do I calculate the height of a table because myTable.GetHeight().GetValue(); throws a nullreference exception because GetHeight() returns null.
First of all table.GetHeight().GetValue() returns null because you are %99 not setting your table's height.
For Example :
var table1 = new Table(1);
var height1 = table1.GetHeight().GetValue(); // This throws exception because we are not setting the height in here.
var table2 = new Table(1).SetHeight(20);
var height2 = table2.GetHeight().GetValue(); // This line returns 20, because you have set the value of height
For your main issue,
You can take the default page size with the below code, and set your table's height
var defaultPageHeight = pdfDocument.GetDefaultPageSize().GetHeight();
var table = new Table(1).UseAllAvailableWidth().SetHeight(defaultPageHeight);
But this wouldnt be a good approach, I think a good approach would be using a TableRenderer
Little Example:
public class CustomTableRenderer : TableRenderer
{
protected Document document;
public class CustomTableRenderer(Table modelElement, Document document) : base(modelElement)
{
this.document = document;
}
public override IRenderer GetNextRenderer()
{
// Add a header everytime a new page is created with this renderer
var header = new Table(1).UseAllAvailableWidth();
header.AddCell(new Cell().Add(new Paragraph("Title")));
document.Add(header);
return new CustomTableRenderer((Table)GetModelElement())
}
public override void Draw(DrawContext drawContext)
{
// This is the part where you create your layout for every time this renderer calls.
var defaultPageHeight = drawContext.GetDocument().GetDefaultPageSize().GetHeight();
// And you can do other things
}
}

Binding Image URIs via Image.SetBinding() not working properly

I'm using the following code snippet to bind a image url to a image object (used as one element in a ViewCell object).
...
Image Picture = new Image()
{
Aspect = Aspect.AspectFit,
HorizontalOptions = LayoutOptions.StartAndExpand
}; // ImageSource.FromUri(new Uri("sImageUrl")))
Picture.SetBinding(Image.SourceProperty, "sImageUrl");
...
The images in the list, for which I'm using that cell view, are not loading always. I was not able to identify the exact reason for the problem, but I think the problem is the load-process (for loading the images from the url/internet)..
Maybe the problem could be solved by setting the url via new Uri(...) as described in the documentation
var webImage = new Image { Aspect = Aspect.AspectFit };
webImage.Source = ImageSource.FromUri(new Uri("https://xamarin.com/content/images/pages/forms/example-app.png"));
Now my question: is there a workaround for binding a uri object? e.g.
...
Image Picture = new Image()
{
Aspect = Aspect.AspectFit,
HorizontalOptions = LayoutOptions.StartAndExpand
}; // ImageSource.FromUri(new Uri("sImageUrl")))
Picture.SetBinding(Image.SourceProperty, ImageSource.FromUri(new Uri("sImageUrl")));
...
I'm working with xamarin studio (version 6.1.2, build 44, update channel "beta", os x).
Would be great if someone got a tipp.
Thanks a lot,
Alex
after some more trying I found a solution.. I'm not sure if it's a secure / professional way.. But for now, it seems to work.
What I did: I implemented my own class "AsyncSrcImage", derived it from Image and added another bindable property:
public class AsyncSrcImage : Image
{
private static String sDefaultURL = "";
public static readonly BindableProperty AsyncImgUrlProperty = BindableProperty.Create(nameof(AsyncImgUrl), typeof(String), typeof(AsyncSrcImage), sDefaultURL);
public String AsyncImgUrl
{
get { return (String)GetValue(AsyncImgUrlProperty); }
set { SetValue(AsyncImgUrlProperty, value); }
}
}
Additionally I adjusted the rendering process with a custom renderer. There I'm loading the image source via new Uri(...) as described in the documentation:
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms;
using System;
[assembly: ExportRenderer(typeof(AsyncSrcImage), typeof(AsyncSrcImageRenderer))]
public class AsyncSrcImageRenderer : ImageRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
{
base.OnElementChanged(e);
AsyncSrcImage oImage = (AsyncSrcImage)Element;
if (oImage != null && oImage.AsyncImgUrl != "")
{
oImage.Source = ImageSource.FromUri(new Uri(oImage.AsyncImgUrl));
}
}
}
Maybe that helps other folks ;)

Automatic update of Button text on change

I'm currently learning scala, and making an encryption program with a basic scala swing UI.
I added 2 swing buttons which text is held by 2 var.
The code looks like this :
var encText = "Encrypt"
var decText = "Decrypt"
def top = new MainFrame {
title = "Data Guardian"
minimumSize = new Dimension(500, 200)
contents = new GridPanel(2, 2) {
hGap = 3; vGap = 3
contents += new Button {
text = encText
reactions += {
case ButtonClicked(_) => Main.startEnc
}
}
contents += new Button {
text = decText
reactions += {
case ButtonClicked(_) => Main.startDec
}
}
}
size = new Dimension(150, 40)
}
Those "text" var will be changed often during the encryption/decryption process by various methods, but when they do change, the text displayed on the buttons doesn't.
I'd like to know a way to make the displayed text of the buttons automatically change when the var that holds that text changes.
Thanks a lot for your insight :)
Make the strings private and write getters/setters that change the button text as a side-effect.
You'll need to give the buttons names, rather than having anonymous instances as you do above.

Eclipse RCP: Set Image in the status line

I am developing an RCP application, I wanted to set the status line. I figured out that I can extend the ActionBarAdvisor class and by overriding the method fillStatusLine() method I can set the status.
private StatusLineContributionItem statusItem;
#Override
protected void fillStatusLine(IStatusLineManager statusLine) {
statusItem = new StatusLineContributionItem("LoggedInStatus");
statusItem.setText("Logged in");
statusLine.add(statusItem);
}
Now, I wish to set image along with it. Is is possible to add image to status line?
You need to override fill(Composite parent) method in your StatusLineContributionItem. There you can add custom components (images, buttons etc. to a status line). For example: http://book.javanb.com/eclipse-rich-client-platform-designing-coding-and-packaging-java-applications-oct-2005/ch17lev1sec7.html
org.eclipsercp.hyperbola/StatusLineContribution
public void fill(Composite parent) {
Label separator = new Label(parent, SWT.SEPARATOR);
label = new CLabel(parent, SWT.SHADOW_NONE);
GC gc = new GC(parent);
gc.setFont(parent.getFont());
FontMetrics fm = gc.getFontMetrics();
Point extent = gc.textExtent(text);
if (widthHint > 0)
widthHint = fm.getAverageCharWidth() * widthHint;
else
widthHint = extent.x;
heightHint = fm.getHeight();
gc.dispose();
StatusLineLayoutData statusLineLayoutData = new StatusLineLayoutData();
statusLineLayoutData.widthHint = widthHint;
statusLineLayoutData.heightHint = heightHint;
label.setLayoutData(statusLineLayoutData);
label.setText(text);
label.setImage(image);
...
}
You chould use the following class: org.eclipse.ui.texteditor.StatusLineContributionItem.class this contains the method setImage(Image image).
It is found in: plugins/org.eclipse.ui.workbench.texteditor_(version).jar of your eclipse installation.
This is class extends: org.eclipse.jface.action.StatusLineContributionItem.class.
Note there are 2 classes named: StatusLineContributionItem.class the other resides in: plugins/org.eclipse.jface_(version).jar and is named: org.eclipse.jface.action.StatusLineContributionItem.class.
This one however does not contain the setImage(Image image) method.
You can then call:
StatusLineManager statusLine = new StatusLineManager();
StatusLineContributionItem i = new StatusLineContributionItem("myid");
i.setText("myText");
i.setImage(SWTResourceManager.getImage(MyClass.class, "config.gif");
...
statusLine.add(i);
...
return statusLine;
If you want complete customization you can use the solution above overriding the fill(Composite composite) method.
Reference:
http://help.eclipse.org/luna/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fui%2Ftexteditor%2FStatusLineContributionItem.html

targeting sprites from a method in the document class - null object reference

I am trying to code a flash app entirely in the document class. I am using GestureWorks with a touch screen. When a user essentially presses a button it calls a method that should hide a specific graphic but not the graphic they touched.
Essentially I need a way to refer to a graphic on the screen using a method besides 'e.target'.
I am receiving this error: Error #1009: Cannot access a property or method of a null object reference.
//This code works
private function photo1SpriteFlickHandler(e:GestureEvent):void {
var openTween:Tween = new Tween(e.target, "x", Strong.easeOut, 232, 970, 5, true);
}
//this code gives me a null object reference
private function photo1SpriteFlickHandler(e:GestureEvent):void {
var openTween:Tween = new Tween(photo1Sprite, "x", Strong.easeOut, 232, 970, 5, true);
}
//photo1Sprite has already been programatically added to the screen as so:
var photo1Sprite = new TouchSprite();
var photo1Loader=new Loader();
photo1Loader.load(new URLRequest("media/photos1/photo1.jpg"));
photo1Loader.contentLoaderInfo.addEventListener(Event.COMPLETE,loaderComplete);
photo1Sprite.x = 232;
photo1Sprite.y = 538;
photo1Sprite.scaleX = .3;
photo1Sprite.scaleY = .3;
photo1Sprite.blobContainerEnabled = true;
photo1Sprite.addEventListener(TouchEvent.TOUCH_DOWN, startDrag_Press);
photo1Sprite.addEventListener(TouchEvent.TOUCH_UP, stopDrag_Release);
photo1Sprite.addChild(photo1Loader);
addChild(photo1Sprite);
It can access photo1Sprite as 'e.target' when the button click happens on the photo1Sprite.
The problem happens when to click one button (not photo1Sprite) and have it effect photo1Sprite.
So I can make photo1Sprite react if my method is attached to it directly using 'e.target' but not if I am trying to call it from a method that was called from another element on the screen.
I'm not sure what the Tween class constructor expects as it first argument. Is it a Sprite instance or is it the name of a Sprite instance? In any case make sure that - in the context of photo1SpriteFlickHandler - photo1Sprite is 1) defined! and 2) refers to the correct thing.