3

I'm trying to have a Syncfusion Popup in my app. Because of the size and for reusability I put the Popup's content into a separate ContentView. However this makes the Binding to the content fail. I made a minimal (not) working example for this with two Popups, one has a Label and the other has the Label moved to a ContentView. This is part of a new Maui App Project in VS, so I will only post the relevant code.

MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:sfPopup="clr-namespace:Syncfusion.Maui.Popup;assembly=Syncfusion.Maui.Popup"
             xmlns:local="clr-namespace:MinimalNotWorkingExample"
             x:Class="MinimalNotWorkingExample.MainPage">

    <ScrollView>
        <VerticalStackLayout>
            <Button
                x:Name="CounterBtn"
                Text="Click me" 
                SemanticProperties.Hint="Counts the number of times you click"
                Clicked="OnCounterClicked"
                HorizontalOptions="Fill" />
            <Button
                x:Name="CounterBtn2"
                Text="Click me" 
                SemanticProperties.Hint="Counts the number of times you click"
                Clicked="CounterBtn_Clicked"
                HorizontalOptions="Fill" />

            <sfPopup:SfPopup x:Name="popup" HeaderTitle="{Binding MyString}" AppearanceMode="OneButton" ShowFooter="True" AutoSizeMode="Both">
                <sfPopup:SfPopup.ContentTemplate>
                    <DataTemplate>
                        <local:MyView Data="{Binding MyString}"/>
                    </DataTemplate>
                </sfPopup:SfPopup.ContentTemplate>
            </sfPopup:SfPopup>
            
            <sfPopup:SfPopup x:Name="popup2" HeaderTitle="{Binding MyString}" AppearanceMode="OneButton" ShowFooter="True" AutoSizeMode="Both">
                <sfPopup:SfPopup.ContentTemplate>
                    <DataTemplate>
                        <VerticalStackLayout>
                            <Label 
                                Text="If you can Read this, the Content was loaded directly. IF you can see the same text below as in the header, the Binding is working."
                                VerticalOptions="Center" 
                                HorizontalOptions="Center"
                                TextColor="Black"/>
                            <Label Text="{Binding MyString}" TextColor="Black"/>
                        </VerticalStackLayout>
                    </DataTemplate>
                </sfPopup:SfPopup.ContentTemplate>
            </sfPopup:SfPopup>
        </VerticalStackLayout>
    </ScrollView>

</ContentPage>

MainPage.cs

namespace MinimalNotWorkingExample
{
    public partial class MainPage : ContentPage
    {
        int count = 0;

        MyViewModel vm = new MyViewModel();

        public MainPage()
        {
            BindingContext = vm;
            InitializeComponent();
        }

        private void OnCounterClicked(object? sender, EventArgs e)
        {
            count++;

            if (count == 1)
                CounterBtn.Text = $"Clicked {count} time";
            else
                CounterBtn.Text = $"Clicked {count} times";

            SemanticScreenReader.Announce(CounterBtn.Text);
            vm.MyString = CounterBtn.Text;
            popup.Show();
        }

        private void CounterBtn_Clicked(object sender, EventArgs e)
        {
            count++;

            if (count == 1)
                CounterBtn2.Text = $"Clicked {count} time";
            else
                CounterBtn2.Text = $"Clicked {count} times";

            SemanticScreenReader.Announce(CounterBtn2.Text);
            vm.MyString = CounterBtn2.Text;
            popup2.Show();
        }
    }
}

MyView.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MinimalNotWorkingExample.MyView">
    <VerticalStackLayout>
        <Label 
            Text="If you can Read this, the ContentView was loaded. IF you can see the same text below as in the header, the Binding is working."
            VerticalOptions="Center" 
            HorizontalOptions="Center"
            TextColor="Black"/>
        <Label 
            Text="{Binding Data}"
            VerticalOptions="Center" 
            HorizontalOptions="Center"
            TextColor="Black"/>
    </VerticalStackLayout>
</ContentView>

MyView.cs

namespace MinimalNotWorkingExample;

public partial class MyView : ContentView
{
    public static readonly BindableProperty DataProperty =
    BindableProperty.Create("Data", typeof(string), typeof(MyView));
    public string Data
    {
        get => (string)GetValue(DataProperty);
        set => SetValue(DataProperty, value);
    }
    public MyView()
    {
        BindingContext = this;
        InitializeComponent();
    }
}

MyViewModel.cs

using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Text;

namespace MinimalNotWorkingExample
{
    public partial class MyViewModel : ObservableObject
    {
        [ObservableProperty]
        public partial string MyString {  get; set; }
    }
}

if you run this code you can see that the binding is only working when the content is set directly and not through a separete ContentView.

1 Answer 1

2

Update after comment

You have to tell MyView.xaml where to search for Data binding. In case you place your view in a namespace named controls

namespace MinimalNotWorkingExample;

public partial class MyView : ContentView
{
   public class CustomClass
   {
      public String Id { get; set; }
      public String Name { get; set; }
   }

   public static readonly BindableProperty DataProperty =
      BindableProperty.Create(
         propertyName: nameof(Data),
         returnType: typeof(CustomClass),
         declaringType: typeof(MyView),
         defaultValue: default(CustomClass));

   public CustomClass Data
   {
      get { return (CustomClass)GetValue(DataProperty); }
      set { SetValue(DataProperty, value); }
   }
   
   public MyView()
   {
      InitializeComponent();
   }
}
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:controls="clr-namespace:MinimalNotWorkingExample.Controls;assembly=MinimalNotWorkingExample"
             x:Class="MinimalNotWorkingExample.MyView">
    <VerticalStackLayout>
        <Label 
            Text="If you can Read this, the ContentView was loaded. IF you can see the same text below as in the header, the Binding is working."
            VerticalOptions="Center" 
            HorizontalOptions="Center"
            TextColor="Black"/>
        <Label 
            Text="{Binding Source={RelativeSource AncestorType={x:Type controls:MyView}}, Path=Data.Name, x:DataType=controls:MyView}"
            VerticalOptions="Center" 
            HorizontalOptions="Center"
            TextColor="Black"/>
    </VerticalStackLayout>
</ContentView>
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you for your reply. The BindingContext=this was a small mistake, my actual code sets it to Data, as it's actually not a string but a class with multiple properties I want to bind to. I just wanted to simplify the example. That being said, do you have a way to change this to a Data class and bind to it's properties in a way that I don't have to use such a long binding every time? Like setting this for the whole file?
I have updated my answer. Unfortunately, (even more if you work with compiled bindings) you would have to set x:DataType with every binding, so there is no shorter way (AFAIK)
Would it be possible to use internal binding? Make a second Data property, bin the first one to the view model like you did, bind the second one to the first one and use it as a proxy to bind the individual properties to? Because my Data class has quite a few properties
@ThorstenSchmitz you can try to set x:DataType on your <ContentView.. x:DataType="controls:MyView" declaration., but I haven't tested on Release mode. In your suggestion, you are setting unnecesary bindings (ViewModel to MyView Data1, MyView Data1 to MyView Data2 and MyView Data2 to your Label Text property) and you would still need to specify your Label where to search for the bind.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.