I have a problem with making a game using Xamarin.Forms and MVVM.
In the game there's a submarine which is controlled by the user and there are mines falling down so the user has to avoid these mines. The mines are generated in runtime using 2 timers, so I represent these with a CollectionView in XAML.
I already made this game using WPF (and also using WinForms) and in that case I used Canvas for the game area (ItemsControl for the mines) and the bindings works well. Now (using Xamarin.Forms) I tried implementing the game area with AbsoluteLayout and with RelativeLayout, but always received eg. the following output (RelativeLayout):
[0:] Binding: '160' cannot be converted to type 'Xamarin.Forms.Constraint'
The current XAML code:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="SubmarineGame.View.GamePage"
Title="Submarine Game">
<ContentPage.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<RelativeLayout Grid.Row="0">
<Image Source="sea.png"
RelativeLayout.WidthConstraint="{ConstraintExpression
Type=RelativeToParent,
Property=Width,
Factor=1}"
RelativeLayout.HeightConstraint="{ConstraintExpression
Type=RelativeToParent,
Property=Height,
Factor=1}"
Aspect="AspectFill" />
<ImageButton Command="{Binding ExitCommand}"
CornerRadius="50"
RelativeLayout.WidthConstraint="{ConstraintExpression Constant=50}"
RelativeLayout.HeightConstraint="{ConstraintExpression Constant=50}"
RelativeLayout.XConstraint="{ConstraintExpression
Type=RelativeToParent,
Property=Width,
Factor=0.9}"
RelativeLayout.YConstraint="{ConstraintExpression
Type=RelativeToParent,
Property=Height,
Factor=0.1}"
Source="pausebutton.png" />
<CollectionView ItemsSource="{Binding Mines}"
BackgroundColor="Transparent"
RelativeLayout.WidthConstraint="{ConstraintExpression
Type=RelativeToParent,
Property=Width,
Factor=1}"
RelativeLayout.HeightConstraint="{ConstraintExpression
Type=RelativeToParent,
Property=Height,
Factor=1}"
FlowDirection="MatchParent">
<CollectionView.ItemTemplate>
<DataTemplate>
<Image RelativeLayout.WidthConstraint="{ConstraintExpression Constant=64}"
RelativeLayout.HeightConstraint="{ConstraintExpression Constant=64}"
RelativeLayout.XConstraint="{Binding X}"
RelativeLayout.YConstraint="{Binding Y}"
Source="nuclearbomb.png" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Image RelativeLayout.WidthConstraint="{ConstraintExpression Constant=64}"
RelativeLayout.HeightConstraint="{ConstraintExpression Constant=64}"
RelativeLayout.XConstraint="{Binding Submarine.X}"
RelativeLayout.YConstraint="{Binding Submarine.Y}"
Source="submarine.png" />
</RelativeLayout>
<StackLayout Orientation="Horizontal" HorizontalOptions="Start" Grid.Row="1">
<Label Text="Game time: " />
<Label Text="{Binding GameTime}" />
</StackLayout>
<StackLayout Orientation="Horizontal" HorizontalOptions="End" Grid.Row="1">
<Label Text="Destroyed mines: " />
<Label Text="{Binding DestroyedMineCount}" />
</StackLayout>
</Grid>
</ContentPage.Content>
</ContentPage>
Submarine and Mines in the ViewModel:
public ObservableCollection<Shape> Mines { get; set; }
public Submarine Submarine { get; set; }
The Shape class:
public class Shape : ViewModelBase
{
private Int32 _x;
private Int32 _y;
public Int32 X
{
get { return _x; }
set
{
if (_x != value)
{
_x = value;
OnPropertyChanged();
}
}
}
public Int32 Y
{
get { return _y; }
set
{
if (_y != value)
{
_y = value;
OnPropertyChanged();
}
}
}
public Int32 Width { get; set; }
public Int32 Height { get; set; }
public Int32 Weight { get; set; }
}
The Submarine class:
public class Submarine : Shape
{
public DelegateCommand StepCommand { get; set; }
}
So the question is how can I solve the conversion problem? Am I using a wrong layout for the game area (and even for the mines)? What method or pattern used in this case by the Xamarin developers to implement the MVVM architecture?
Thanks for your time and sorry for my English!
CodePudding user response:
From the error:
[0:] Binding: '160' cannot be converted to type 'Xamarin.Forms.Constraint'
You can see that it can't convert the integer to the type Constraint
that is expected by the binding expression.
When you do this:
<Image RelativeLayout.WidthConstraint="{ConstraintExpression Constant=64}"
RelativeLayout.HeightConstraint="{ConstraintExpression Constant=64}"
RelativeLayout.XConstraint="{Binding X}"
RelativeLayout.YConstraint="{Binding Y}"
Source="nuclearbomb.png" />
You're binding to your integer X and Y when the type expected is Constraint
.
Personally I would avoid using constraints for layout and prefer Grid
instead but you can get around this error if you wish by changing the type of the constraint bindings (X
,Y
, etc) to Constraint
and using the helper methods to convert the numerical values
Constraint.Constant(myConstraintAsADouble)
.