Binding to Windows::UI::Xaml::GridLength in C++/CX - windows-runtime

I am trying to bind to a GridLength instance in a Windows Store app (compiled with the Visual Studio 2013 compiler) in C++/CX, but for some reason I keep getting the following error at runtime:
Error: Converter failed to convert value of type 'Windows.Foundation.IReference`1<Windows.UI.Xaml.GridLength>' to type 'GridLength'; BindingExpression: Path='MyHeight' DataItem='MyNamespace.MyObject'; target element is 'Windows.UI.Xaml.Controls.RowDefinition' (Name='null'); target property is 'Height' (type 'GridLength').
My code essentially looks like:
namespace MyNamespace
{
[Windows::UI::Xaml::Data::Bindable]
public ref class MyObject sealed
{
property Windows::UI::Xaml::GridLength MyHeight
{
Windows::UI::Xaml::GridLength get() { return myHeight; }
}
}
}
and my XAML file essentially looks like:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="{Binding MyHeight}"/>
</Grid.RowDefinitions>
</Grid>
Just FYI, other properties in my class are binding properly. The issue appears to only be with the GridLength value struct. It is obviously finding the property correctly, but for some reason it can't match up the types.

A RowDefinition is not a FrameworkElement, so it doesn't have a DataContext. Binding won't work here. You can put a Rectangle in that row though, set the row height to Auto and bind the Rectangle.Height to a property you want. That could work for some scenarios. For others there might be better solutions, but you would need to specify what exactly you are trying to achieve.

So, it appears that the property type projection isn't working as you or I would expect it to. It's wrapping the GridLength property in an IReference<T> (or, in C#, Nullable<T>). Try binding to MyHeight.Value.

Related

Set view element BindingContext - mvvm cross

Is it possible to set element data context in MvvmCross?
Suppose I have:
<RelativeLayout>
<TextView/> <TextView/>
</RelativeLayout>
and I'd like to set RelativeLayout data context to viewmodel property.
XAML equivalent of:
<Grid DataContext="{Binding someProperty}">
<TextBlock/> <TextBlock/>
</Grid>
You can't currently do this directly in a single axml file in MvvmCross at present.
However:
You can use MvxFrameControl to load a sub-axml file (a bit like an include) and then set the DataContext for everything inside that sub-view
MvvmCross is open source - so you can extend and adapt it...

Flex 4.6 setting selectedChild= with a bound Variable from a Component

I'm getting the following error:
1067: Implicit coercion of a value of type String to an unrelated type mx.core:INavigatorContent.
Which is located in my main application at the line where I set the selectedChild=
Here's my code for my viewstack which is in my main application:
<mx:ViewStack id="mainViewStack"
width="100%" height="100%"
selectedChild="{topViewControlComponent.selectedChild}">
My component contains the following:
[Bindable]
public var selectedChild:String;
protected function changeView2(child:String):void
{
this.selectedChild = child;
}
<s:Button styleName="controlBarButton"
label="Events"
click="changeView2('userEvents');"/>
I got this to work when I set the viewstack navigator content base off of selectIndex and using an integer...worked fine. But I would rather call them by the id of the Navigator content so that they don't have to be in specific order, if this is possible. Or maybe there's a better way to go about this...Thanks for any help!
The selectedChild property on the ViewStack takes an actual view as its argument, not the name of a view. Using selectedIndex with an int will work fine, or you could call a function in your main application that maps between id and view instance.
Edit: As you said in the comments, you can use click="mainViewStack.selectedChild=userEvents" to set the view as desired.
However, your code in the question is acting like this:
click="mainViewStack.selectedChild='userEvents'"

MVVMCross - display view inside view

I cannot seem to find any simple examples of this.
I have a WPF UI that I wish to display a view as a child control within another view. The MvxWpfView inherits from UserControl so it should be possible, however I cannot seem to work out how to do the binding.
I get a BindingExpression path error, as it cannot find ChildView property in my ParentViewModel.
So how do I bind a view to control content?
Firstly it's possible that you just need to add the BViewModel you want displayed on AView as a property on ViewModelA
E.g.
public class AViewModel: MvxViewModel
{
public BViewModel ChildViewModel
{
get;set;//With appropriate property changed notifiers etc.
}
}
Then inside AView you just add a BView, and you can set the datacontext of BView as follows:
<UserControl DataContext="{Binding ChildViewModel}"/>
However, if you want something more flexible (and you want the presentation handled differently for different platforms) then you will need to use a Custom Presenter
Inside your setup.cs you override CreateViewPresenter:
protected override IMvxWpfViewPresenter CreateViewPresenter(Frame rootFrame)
{
return new CustomPresenter(contentControl);
}
Now create the class CustomPresenter you need to inherit from an existing presenter. You can choose between the one it's probably using already SimpleWpfPresenter or you might want to go back a bit more to basics and use the abstract implementation
The job of the presenter is to take the viewmodel you have asked it to present, and display it "somehow". Normally that mean identify a matching view, and bind the two together.
In your case what you want to do is take an existing view, and bind a part of it to the second view mode.
This shows how I have done this in WinRT - but the idea is very similar!
public override void Show(MvxViewModelRequest request)
{
if (request.ViewModelType == typeof (AddRoomViewModel))
{
var loader = Mvx.Resolve<IMvxViewModelLoader>();
var vm = loader.LoadViewModel(request, new MvxBundle());
if (_rootFrame.SourcePageType == typeof (HomeView))
{
HomeView view = _rootFrame.Content as HomeView;
view.ShowAddRoom(vm);
}
}
else
{
base.Show(request);
}
}
So what I'm doing is I'm saying if you want me to present ViewModel AddRoom, and I have a reference to the HomeView then I'm going to just pass the ViewModel straight to the view.
Inside HomeView I simply set the data context, and do any view logic I may need to do (such as making something visible now)
internal void ShowAddRoom(Cirrious.MvvmCross.ViewModels.IMvxViewModel vm)
{
AddRoomView.DataContext = vm;
}
Hopefully that makes sense! It's well worth putting a breakpoint in the show method of the presenters so you get a feel how they work - they are really simple when you get your head around them, and very powerful.

How to use contents = to add to a Scala Panel?

Sorry this must be a very silly question.. but everywhere I've been seeing Scala code examples where you just do
contents+= on a BoxPanel or some layout Panel. I figured because they have contents as mutable.buffer so you can just add and remove components.
But how do you add a component to Scala Panel? It accepts a seq so do you have to give it a list or something? I know you can just call peer.add but I want to see how Scala code does it. :)
For example contents = new Button {} isn't working.
Sorry for this simple question I'm very new to Scala..
EDIT:
Thanks for the replies. My question now though becomes.. can you ever just have a class extending Panel? Would you be able to set contents for it at all? Or is it never done and everyone always just uses the Panels associated with a layout manager?
The Panel class itself is abstract, meaning it can't be instantiated directly, and is intended as a "base" for concrete implementations of panels.
It doesn't seem to have a "common" method for adding components probably because each subclass implements its own, sometimes mutually incompatible custom one:
BoxPanel, as you've noted, has a settable Buffer,
FlowPanel seems to mandate adding components as constructor arguments,
GridBagLayout and some others implement addition via the layout Map,
etc.
As you might see from the above examples, it would be hard to specify what a general "add" method would mean in all of those cases.
EDIT in response: of course you can, there's nothing stopping you from subclassing a Panel yourself and override the contents method, e.g.:
val myPanel = new Panel() {
private val myContents = (new Content += new Button())
override def contents = myContents
}
You can also use Panel as a type parameter for your methods that process panels in a general way, etc. It's just that you can't have an instance that's just a Panel, because, again, the class is abstract, so you can't instantiate it.
Note that this is not unique to Scala, if JPanel was abstract in Java (like Component is) the outcome would be the same.
I want to see how Scala code does it.
https://github.com/scala/scala-swing/blob/v1.0.0-RC2/src/main/scala/scala/swing/Container.scala#L35
I, too, practiced on some Swing code when I first learned some Scala.
Here is a Panel component that renders itself as a simple game grid:
https://github.com/som-snytt/House-of-Mirrors-Fork/blob/act/src/main/scala/hom/LightBox.scala#L286
To see how the Scala and Swing pieces fit together, see SuperMixin:
https://github.com/scala/scala-swing/blob/v1.0.0-RC2/src/main/scala/scala/swing/Component.scala#L51
Assembly:
https://github.com/som-snytt/House-of-Mirrors-Fork/blob/act/src/main/scala/hom/HouseOfMirrors.scala#L18
This is what you asked about directly:
https://github.com/som-snytt/House-of-Mirrors-Fork/blob/act/src/main/scala/hom/HouseOfMirrors.scala#L45
If you have a button:
val button=new Button{
text="Click me!"
}
or
val label=new Label{
text="Look, i'm a label!"
}
or
object myField extends TextField{ columns=2 }
then you just use:
contents=new BoxPanel(Orientation.Vertical){
contents+=button
border=Swing.EmptyBorder(10,20,10,20)
}
or in a more simpler form:
contents=new FlowPanel(){
contents+=new Label("This is my button:")
contents+=new Button("Click me!")
border=Swing.EmptyBorder(10,20,10,20)
}

MVVMCross ValueConverter Parameter

Hello MVVMCross community,
My question is about ValueConverters parameters:
Is there any way to pass a variable to a Value Converter rather than a constant value as a ConverterParameter?
Something like:
<EditText
android:id="#+id/editPrice"
...
local:MvxBind="Text Price; Enabled IsPriceEnabled; BackgroundColor IsPriceEnabled, Converter=Enabled2MvxColor, ConverterParameter=Price"/>
or even pass the whole object for example:
<EditText
android:id="#+id/editPrice"
...
local:MvxBind="Text Price; Enabled IsPriceEnabled; BackgroundColor IsPriceEnabled, Converter=Enabled2MvxColor, ConverterParameter=editPrice"/>
TIA,
When using Windows/XAML IValueConverter you can't really pass data-bound entries into the value converter parameter.
However, using the Tibet binding extensions within MvvmCross, you should be able to do this if you use the form:
local:MvxBind="BackgroundColor Enabled2MvxColor(IsPriceEnabled, Price)"
For more on this - and on whole object binding, see https://github.com/MvvmCross/MvvmCross/wiki/Databinding
I had to do something similar couple of days ago: it's rather convoluted:
<controls:OptionItemControl
ItemTitle="{Binding Path=AccountSettings, Converter={StaticResource ContentItemConverter}, Mode=OneTime,
ConverterParameter=DataRoaming.Text}"
ItemInfo="{Binding Path=AccountSettings, Converter={StaticResource ContentItemConverter}, Mode=OneTime,
ConverterParameter=DataRoaming.Info}"
ItemValue="{Binding AccountSettings.DataRoaming, Mode=TwoWay}"
/>
So my ViewModel has a property AccountSettings, which is a class that has another property DataRoaming, which has several properties like .Text, .Info
I am sure there is much easier way to do what I needed it to do, but I wanted to get from using magic string; I didn't get it at the end, but at-least this makes it easier for me to read and figure out.
so in converter I get the parameter, split it; then from value type and I can navigate through the properties and get the actual value from the class. Of course I could have as well called a method.
Hope this might give you some ideas.