Conditional Databinding in Xamarin.iOS using MvvmCross - xamarin

Here is the scenario/dilemma I'm currently in.
I have a UIImageView that contains a placeholder Image.
myImageView = new MvxImageView
{
Image = ImagePlaceHolder
};
I bind a MvxImageViewLoader from the View to a string property(URL)in the ViewModel.
imageLoader = new MvxImageViewLoader(() => myImageView);
All of this works just fine and properly displays the image when a valid URL is present.
The issue is this, Say the bound URL/imageLoader does not contain a string.
Instead of defaulting back to the placeholder image, I would like to display a UILabel in Place of the Image View.
Whereby this UILabel, will also be bound to some text.
....
Now that I think about it, I believe a possible solution would be to create a boolean property on the ViewModel and have its status update depending on the value of the URL i.e
string.IsNullOrWhiteSpace(URL).
Then I could have the UILabel's.Hidden property bounded to this boolean property in the ViewModel to determine whether or not to show or hide the Label.
Not sure If I should delete this or let it be... it may be helpful to someone in the future.
.. I guess sometimes its best to talk it out... even if you're typing it out.

Related

How can I display a imageView only once in a cell of tableView?

I'm developing a application which uses a TableView. And I'd like to add a ImageView for helping operation of user on detail view. In other words when user tap a cell in the tableview, the imageview is showed on the detail view only once for helping operation of user.
What should I do to implement such specifications?
Perhaps you could give your TableViewController a BOOL property (for example, called shouldHideHelperImage) it could initialize to NO. When opening the detail view, you could use that property to determine whether your ImageView should be hidden or not.
[imageView setHidden:[<TableViewContoller name> shouldHideHelperImage]];
[<TableViewController name> setShouldHideHelperImage:YES];
You would have to save that value to file for persistance. The reason I recommended making this a property of the TableViewController rather than your detailViewController is just so that it would have to be saved and recalled less often.
I hope that helps! - though by now you've probably already solved it.

Storyboard change Target Control

I have created a Storyboard through Expression Blend. The Storyboard animates an Ellipse as a sortof placeholder for now. Now that I am back in Visual Studio, how can I make the Storyboard do the exact same thing but to a different control? I have a list of images:
private List<Image> items = new List<Image>();
Each object in items has been assigned with a name using the Name property:
items[i].Name = i.ToString();
'i' in this case is the counter.
How do I therefore make the Storyboard target "one" specific object within the list for the moment. Later, I shall try to make the Storyboard do the same for all of them.
Any help is highly appreciated.
I fixed the problem by having a Storyboard Completed event and changing the target using:
Storyboard.SetTargetName();

Manual Cocoa Binding not changing Observed KeyPath

I'm changing a cocoa binding programatically. I'm binding a NSTextField's value to the selection of an ArrayController. After I manually change the binding, I'm getting the "not key-value coding compliant for the key.." error, with the key being the old key, not the new one.
Check out the code:
NSTextField *textField = [self listTextField];
NSDictionary *currentBindInfo = [textFieldTableViewCell infoForBinding:NSValueBinding];
NSLog(#"pre-change bindings for textField: %#", currentBindInfo);
/* Change the binding. [Tried unbind: first, no difference] */
[textField bind:NSValueBinding
toObject:[currentBindInfo valueForKey:NSObservedObjectKey]
withKeyPath:#"objectValue.iLifeProductName"
options:[currentBindInfo valueForKey:NSOptionsKey]];
/* Log the info so we can confirm it changed. debugging. */
NSLog(#"post-change bindings for textField: %#", [textFieldTableViewCell infoForBinding:NSValueBinding]);
To troubleshoot, I call 'infoForBinding' before and after the change and it looks to be changed correctly. I can see the old value, then I call bind:toObject... and dump the infoForBinding a second time, and the value has changed for the binding:
2011-07-06 22:36:23.137 My App 2011[14640:407] pre-change bindings for listTextFieldTableViewCell: {
NSObservedKeyPath = "selection.osxProductName";
NSObservedObject = "...sameTextField... 0x4009cc380>";
NSOptions = {...same... };
}
2011-07-06 22:36:23.138 My App 2011[14640:407] post-change bindings for listTextFieldTableViewCell: {
NSObservedKeyPath = "selection.iLifeProductName";
NSObservedObject = "...sameTextField... 0x4009cc380>";
NSOptions = {...same... };
}
But the code is still calling the original key:
2011-07-06 22:36:23.231 My App 2011[14640:407] [ valueForUndefinedKey:]: the entity ILifeVersion is not key value coding-compliant for the key "osxProductName".
--
The NSArrayController is bound to a ManagedObjectContext, the entity name is being changed earlier with this:
[[self listAC] setEntityName:entityName];
Is the original keyValuePath being cached somewhere that I need to clear out? Is there a message like willChange/didChangeValueForKeyValuePath that I need to send to the binding or arrayController when I change the observed keypath?
Ideas?
Thanks!
As #noa pointed out, you’re looking at the binding on the cell, but changing the binding on its control. That’s bound (ahem) to cause problems.
Replace this:
[textField bind:NSValueBinding
toObject:[currentBindInfo valueForKey:NSObservedObjectKey]
withKeyPath:#"objectValue.iLifeProductName"
options:[currentBindInfo valueForKey:NSOptionsKey]];
with this:
[textFieldTableViewCell bind:NSValueBinding
toObject:[currentBindInfo valueForKey:NSObservedObjectKey]
withKeyPath:#"objectValue.iLifeProductName"
options:[currentBindInfo valueForKey:NSOptionsKey]];
And see if it works better.
The explanation for this is a bit arcane, and I’m doing it from memory, so please excuse me if I get some of the details wrong.
Because NSControls and their NSCell works so closely together, you can actually bind to either the control or the cell in most instances, and you’ll get very similar results. That is, there’s code in the control to call the proper methods on its NSCell if the control’s been bound to, and vice-versa.
This means that if, in XIB, you bind to one or the other things will work, which is good. It also means you can bind to a cell in cases where you have multiple cells per view, so that’s good. HOWEVER, it can lead to confusion, because in fact you can actually bind to both your view and its cell, and in fact bind them in different ways, and then they’ll crosstalk.
In your example, I believe you’re adding a second binding to the NSControl in addition to the one on its NSCell. You’re doubly-bound. That’s no good.
In terms of best practice, I try to bind only to NSControls unless I have a good reason to drop down to NSCells. Partly because it matches what I do in XIB, partly because any standard helps reduce exactly this problem, and partly because NSCells are being gently deprecated.

Cocoa - How to bind width of a NSView in InterfaceBuilder?

I'm trying to create a simple application that draws a grid in a custom view.
The custom view size is fixed (it doesn't depend on the size of the window).
The custom view is embedded in a scroll view to be able to explore the grid when the scroll view can't display the entire custom view.
Now i want to add sliders for controlling the grid parameters (nb raws, nb columns, tile width, tile height, ...), and these parameters influence the size of the custom view.
As an experiment, i'm trying to bind one slider's value to the width of my custom view but fail to find a way to do it.
How am i supposed to do this sort of things ?
Is it possible to do it in InterfaceBuilder ? I expected to find a width binding in Bindings Inspector Window but it's not there, curiously ;-)
Thanks.
You can't bind the width of a plain NSView, and binding to a property of a view is always a bad idea. View properties are seldom observable. Moreover, there is no width property; it's one member of the structure that is the value of the frame property, which you must set all at once or not at all.
As for exposing bindings in your custom view, you can do that, provided you keep the properties observable (which consists of little more than only changing the property's value using its setter). You'll need to expose the bindings in your view class's initialize method, and you'll need to write an IBPlugin.
See also the Cocoa Bindings Programming Topics.

How can my code get notified when the user pastes or drags an image into NSImageView?

I have an instance of NSImageView. I have told InterfaceBuilder to allow the user to paste or drag an image into this view. This works. However, I don't see a way in the NSImageView or related documentation to get notified when this actually happens. I was expecting a delegate or some such, but I have been unable to find it. Any ideas?
This is what Cocoa Bindings does best.
Instead of talking to the view, simply have a property whose value is an image, and bind the image view's image binding to it; then, when you want to change the image in the image view yourself, all you have to do is set the value of the property, and the image view will notice the change.
The user pasting or dragging into the image view is essentially the same thing, partly in reverse: The paste or drop will change the value of the image view, which will then set the value of your property, which will cause anything else bound to it to notice the change and pick up the new value as before.
Aside from ripping out your existing send-explicit-messages-to-views code, this will require almost no code work: The only code you need is for your property. You'll hook up the Binding in IB.
See the Key-Value Coding Programming Guide and the Cocoa Bindings Programming Topics.
As for me the better way to override function
-(void)paste:(id)sender
But only if you have it in NSView based class which has NSResponder as parent

Resources