Forum Xamarin.Forms

Announcement:

The Xamarin Forums have officially moved to the new Microsoft Q&A experience. Microsoft Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

To create new threads and ask questions head over to Microsoft Q&A for .NET and get involved today.

Howto convert from C# code to XAML

JensBohrmannJensBohrmann DEMember
edited October 2015 in Xamarin.Forms

Hi,

I am new to Xamarin and implemented some examples in "pure" c# code.
Now I am trying to "convert" my code to XAML.

I have a mainpage that passes an object containing data to several detailpages.
This is done by passing the object to the constructor of the detailpage.
The detailpage contains a grid with two rows.
There I have a slider that changes the "Value"-property of my object and
a label that visualizes the current value.

Here is my model class:

public class ObservableSensorClass : INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;

    SensorClass sensor;

    public ObservableSensorClass() {
        sensor = new SensorClass();
    }


    public string Value {
        set {
            if (!value.Equals(sensor.Value, StringComparison.Ordinal)) {
                sensor.Value = value;
                OnPropertyChanged("Value");
            }
        }
        get {
            return sensor.Value;
        }
    }

    void OnPropertyChanged([CallerMemberName] string propertyName = null) {
        var handler = PropertyChanged;
        if (handler != null) {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Here is the c# Version of the detailpage:

public SensorValuesDetailPage(ObservableSensorClass sensor) {
    this.Title = "Werte";
    Grid grid = new Grid {
        VerticalOptions = LayoutOptions.FillAndExpand,
        RowDefinitions =  { new RowDefinition { Height = GridLength.Auto }, new RowDefinition { Height = GridLength.Auto } },
        ColumnDefinitions = { new ColumnDefinition { Width = GridLength.Auto } }
    };

    this.BindingContext = sensor;

    Slider slider = new Slider { Minimum = 0, Maximum = 100, Value = Int32.Parse(sensor.Value),
        VerticalOptions = LayoutOptions.CenterAndExpand, WidthRequest = 300  };

    slider.ValueChanged += (sender, e) => {
        sensor.Value = e.NewValue.ToString();
    };

    grid.Children.Add(slider,1 , 1);

    Label valueLabel = new Label { Text = sensor.Value };

    valueLabel.SetBinding(Label.TextProperty, "Value");
    grid.Children.Add(valueLabel, 1, 2);
    Content = grid;
}

And here is the XAML-Version:

CS:

public partial class SensorValueDetailPage : ContentPage {
        ObservableSensorClass sensor;
        public SensorValueDetailPage(ObservableSensorClass sensor) {
            this.sensor = sensor;
            InitializeComponent();
        }

        void SliderValueChanged(object sender, ValueChangedEventArgs e) {
            sensor.Value = e.NewValue.ToString();
        }
  }

XAML:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="UIDesign.SensorValueDetailPage" BindingContext="sensor" Title="Values">
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>

    <Slider x:Name="slider" Minimum="0" Maximum="100" Value="0" VerticalOptions="CenterAndExpand" ValueChanged="SliderValueChanged" WidthRequest="300" Grid.Row="1" Grid.Column="0"></Slider>
    <Label Text="{Binding Value}" VerticalOptions="Center" HorizontalOptions="Center" Grid.Row="2" Grid.Column="0"/>


  </Grid>
</ContentPage>

The problem I have is the Binding. How can I bind the sensor object from the constructor in the XAML-part? "{Binding Value}" is not working.

Best Answer

  • PatrickMcCurleyPatrickMcCurley AUMember ✭✭
    Accepted Answer

    BindingContext="sensor"

    BindingContext asks for an object, not some sort of variable reference. What you have done here is set your Bindings to an instance of the string 'sensor'.

    Typical usage of BindingContext would be something like

    <ContentPage >
        <ContentPage.BindingContext>
            <ObservableSensorClass></ObservableSensorClass>
        </ContentPage.BindingContext>
         ...
    </ContentPage >
    

    Although this will instantiate a new ObservableSensorClass with a default constructor. I see that you are constructor injecting this instead in your ContentPage, so the best approach would be to do what Sami said and set it directly in your codebehind and not worry about setting any BindingContext in Xaml.

Answers

  • SKallSKall USMember ✭✭✭✭

    You're not assigning the BindingContext in your XAML code behind. Also why don't you change the Value property to something that you bind directly to the slider? If you need it as string then IValueConverter would be a little more elegant solution as this way you don't need any code behind for the page.

  • JensBohrmannJensBohrmann DEMember
    edited October 2015

    Thanks for your reply.
    I assigned the BindingContext in the ContentPage as I thought it would be inherited to all elements in the page. Is that not correct? I was not sure if it is correct to assign the Name of the field in my code behind.

  • SKallSKall USMember ✭✭✭✭
    edited October 2015

    I don't see it in the code you posted. Try replacing this:

    this.sensor = sensor;
    

    with this:

    this.BindingContext = this.sensor = sensor;
    

    EDIT: I see it's part of the XAML. Still worth a try to see if the XAML binding actually works.

  • PatrickMcCurleyPatrickMcCurley AUMember ✭✭
    Accepted Answer

    BindingContext="sensor"

    BindingContext asks for an object, not some sort of variable reference. What you have done here is set your Bindings to an instance of the string 'sensor'.

    Typical usage of BindingContext would be something like

    <ContentPage >
        <ContentPage.BindingContext>
            <ObservableSensorClass></ObservableSensorClass>
        </ContentPage.BindingContext>
         ...
    </ContentPage >
    

    Although this will instantiate a new ObservableSensorClass with a default constructor. I see that you are constructor injecting this instead in your ContentPage, so the best approach would be to do what Sami said and set it directly in your codebehind and not worry about setting any BindingContext in Xaml.

  • JensBohrmannJensBohrmann DEMember

    It works.

    Thank you both.

Sign In or Register to comment.