I have a frame, the IsVisible is binded to a property in my model view that is set to false. when I change the flyout in my shell, the frame makes an appearance as the shell flyout is closing. Any idea why this is happening ?
// in my model view this is the property
public bool ShowPanel{ get { return _showPanel; } set { _showPanel =
value; OnPropertyChange(); } }
// in my view this is the panel
<Frame IsVisible="{Binding ShowPanel}" BackgroundColor="White" BorderColor="Purple" AbsoluteLayout.LayoutFlags="PositionProportional" WidthRequest="100" HeightRequest="200" AbsoluteLayout.LayoutBounds="0,0,200,250">
<local:ExtendedListView ItemTapped="ExtendedListView_ItemTapped" ItemsSource="{Binding AllItems}" IsVisible="{Binding ShowPanel}" SelectionMode="None" HorizontalScrollBarVisibility="Always" HorizontalOptions="Fill" VerticalOptions="Fill" BackgroundColor="Transparent">
<local:ExtendedListView.ItemTemplate >
<DataTemplate>
<ViewCell>
<Grid Padding="0">
<Grid.RowDefinitions>
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10*"></ColumnDefinition>
<ColumnDefinition Width="10*"></ColumnDefinition>
<ColumnDefinition Width="20*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Image.Source="{Binding ImageUrl}" HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand" WidthRequest="50" HeightRequest="50" x:DataType="local1:ServiceLayers"></Image>
<CheckBox Grid.Column="1" IsChecked="{Binding IsVisible, Mode=TwoWay}" Color="Purple" VerticalOptions="Center" HorizontalOptions="Center" x:DataType="local1:ServiceLayers"></CheckBox>
<Label Padding="-5,0,0,0" HorizontalOptions="StartAndExpand" FontAttributes="Bold" TextColor="Black" Grid.Row="0" Grid.Column="2" HorizontalTextAlignment="Start" Text="{Binding Name}" x:DataType="local1:Service"></Label>
<Label></Label>
</Grid>
</ViewCell>
</DataTemplate>
</local:ExtendedListView.ItemTemplate>
</local:ExtendedListView>
</Frame>
// In the View Class
protected override bool OnBackButtonPressed() {
await Shell.Current.GoToAsync($"//{nameof(MainPage)}");
return true;
}
If the BindingContext is removed/changed as you navigate away from the page, the Frame would appear as the binding is invalidated and updated by the binding engine. You have two options:
Don't manually clear the BindingContext from the page as the navigation lifecycle and GC should clean up those resources on their own.
Use binding fallbacks to define behavior when the binding source can't be resolved (because you've nulled the BindingContext) or the binding source is resolved but the bound property is null.
Related
In a Xamarin Forms(MAUI) project I would like to add a Grid with some prices inside another Grid placed in a CollectionView
The Grid is like below and I have created a function which returns a Grid. This works fine in an ordinary stacklayout : where I create the grid and add it as a Child of PriceData.
How do i accomplish that in a ItemTemplate of a CollectionView at runtime placing the grid where the placeholder RIGHTHERE I WANT TO ADD A GRID are
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="5" Margin="20,20,20,20" >
<Grid.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Path=BindingContext.GotoDetailPage, Source={x:Reference Page}}" CommandParameter="{Binding .}" />
</Grid.GestureRecognizers>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"></ColumnDefinition>
<ColumnDefinition Width="5*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Image Grid.Column="0" Grid.Row="0" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" Aspect="Fill" WidthRequest="60" HeightRequest="60" Source="{Binding .,Converter={StaticResource ImageConverter}}"></Image>
<StackLayout Grid.Column="1" Grid.Row="0">
<Label Text="{Binding Title}" />
<Label Text="{Binding BodyText}" />
<<RIGHTHERE I WANT TO ADD A GRID>>
</StackLayout>
<BoxView Grid.Row="1" Grid.ColumnSpan="2" HeightRequest="1" BackgroundColor="LightGray"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
Sorry if the question was unprecise.
The issue was to manipulate with a Grid placed in a CollectionView.ItemTemplate which was bound to a datasource.
I solved it by creating a ContentView with a StackLayout.
The model was passed as a BindableProperty and
then on propertyChanged I created a Grid and added it as a child of the StackLayout
I have this ListView:
<ListView x:Name="listview_items"
Margin="0,10,0,0"
VerticalScrollBarVisibility="Always"
HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="5"/>
</Grid.ColumnDefinitions>
<Label Text="{Binding itemText}"
FontSize="22"
Margin="0,5,0,5"
FontFamily="Font_11"
TextColor="#424242">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"/>
</Label.GestureRecognizers>
</Label>
<CheckBox
Color="#97A5AD"
IsChecked="{Binding isChecked}"
CheckedChanged="chk_accept_shipment_CheckedChanged"
Grid.Column="1"
Scale="1"
HorizontalOptions="End"
Margin="0,0,0,0"
x:Uid="{Binding itemID}"
x:Name="{Binding itemID}"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
As you can see, it contains a Label and a CheckBox, when the user checks the checkbox, I gets checked. But now, I have a gesture recognizer attached to the label. When the user taps the label, I want to find out which checkbox is next to the label and also check it (as if the user actually clicked the checkbox).
How do I find the corresponding checkbox to the label next to it?
I would personally bind the IsChecked property to my ViewModel.
Example:
<StackLayout
HorizontalOptions="Start"
Orientation="Horizontal">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding SelectAllCategoriesCommand}" NumberOfTapsRequired="1" />
</StackLayout.GestureRecognizers>
<CheckBox IsChecked="{Binding IsAllCategoriesSelected}" />
<Label Text="Select All Categories" />
</StackLayout>
The binded property can be something like :
private bool _isAllCategoriesSelected;
public bool IsAllCategoriesSelected
{
get => _isAllCategoriesSelected;
set
{
_isAllCategoriesSelected = value;
RaisePropertyChanged(() => IsAllCategoriesSelected);
}
}
First you have to pass CommandParameter in tap so you can get that in TapGestureRecognizer_Tapped In that you will get which Item table click so according that you have to check check box
<Label.GestureRecognizers>
<TapGestureRecognizer CommandParameter="{Binding itemID}" Tapped="TapGestureRecognizer_Tapped"/>
</Label.GestureRecognizers>
async void TapGestureRecognizer_Tapped(System.Object sender, System.EventArgs e)
{
var d = (TappedEventArgs)e;
var data = d.Parameter as int;//yor itemID type
}
I've only recently started Xamarin and I'm having trouble figuring out how to design a few blocks. I'm trying to create some simple buttons to navigate with and it was decent (picture 2). But as soon as I tried binding it to a data, the design basically ran off (picture 1). Any suggestions?
Image of the problem
Image of the attempt
Below are the codes for picture 1:
<ListView x:Name="displayCourses" ItemsSource="{Binding CourseName}">
<ListView.Header>
<Grid HorizontalOptions="Center">
<!--<Button Text="{Binding CourseName}" BackgroundColor="#ea3e15"
CornerRadius="20" WidthRequest="290" HeightRequest="130"
FontAttributes="Bold" FontSize="26" Clicked="NextPage"
/>-->
</Grid>
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Button Text="{Binding CourseName}" BackgroundColor="#ea3e15" TextColor="#fff"
CornerRadius="20"
FontAttributes="Bold" FontSize="26"
/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
CS codes linking the data together
protected async override void OnAppearing()
{
base.OnAppearing();
displayCourses.ItemsSource = await firebaseHelper.GetCourses();
}
public async Task<List<Course>> GetCourses()
{
FirebaseClient firebase = new FirebaseClient("https://pra-ece32-default-rtdb.firebaseio.com/");
return (await firebase
.Child("Courses")
.OnceAsync<Course>()).Select(item => new Course
{
CourseName = item.Object.CourseName,
CourseID = item.Object.CourseID,
ExamDate = item.Object.ExamDate,
}).ToList();
}
The width of a row inside the listview will always take up the entire width of the listview itself. There is no way to have extra space between the end of a Row and the edge of the listview, nor would that make any sense.
But you can use Grid to meet your requirement. Please set ListView HasUnevenRow="True" to automatically size row height to fit content.
<ListView
x:Name="displayCourses"
HasUnevenRows="True"
ItemsSource="{Binding courses}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button
Grid.Column="1"
Margin="20"
BackgroundColor="#ea3e15"
CornerRadius="20"
FontAttributes="Bold"
FontSize="26"
HeightRequest="50"
Text="{Binding coursename}"
TextColor="#fff"
WidthRequest="200" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Hello I’m having an issue with binding a list of string to my Carousel View
First I have a list of an object I get from my server
public class PostObject
{
public string PostOwner { get; set; }
public string Id { get; set; }
public string Post { get; set; }
public string ProfileImage { get; set; }
public List<string> PostImages { get; set; }
}
List<PostObject> posts = new List<PostObject>();
This works as I expected.
Next I have a card view I created and within the card view I want to have a Carousel View.
So I have setup my Xaml like this (omitting the parts that works for clarity)
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:ImageCircle.Forms.Plugin.Abstractions;assembly=ImageCircle.Forms.Plugin"
NavigationPage.HasNavigationBar="True"
NavigationPage.HasBackButton="False"
NavigationPage.BackButtonTitle="Back"
Title="amici"
x:Class="amici.Posts">
<NavigationPage.TitleView>
<StackLayout Orientation="Horizontal" VerticalOptions="Center" Spacing="10" >
<Label x:Name="GroupTitle" TextColor="White" FontSize="Medium"/>
</StackLayout>
</NavigationPage.TitleView>
<ContentPage.ToolbarItems>
<ToolbarItem Name="iconexample" Icon="settings.png" Priority="0" Order="Primary" />
</ContentPage.ToolbarItems>
<ContentPage.Content>
<StackLayout>
<ListView x:Name="ItemsListView"
VerticalOptions="FillAndExpand"
HasUnevenRows="true"
IsPullToRefreshEnabled="true"
IsRefreshing="{Binding IsBusy, Mode=OneWay}"
CachingStrategy="RecycleElement">
<!--ItemSelected="OnItemSelected"-->
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell >
<StackLayout Padding="10">
<Frame x:Name="myframe" HasShadow="True" >
<Grid HorizontalOptions="FillAndExpand" RowSpacing="0" ColumnSpacing="0" >
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="20" />
<RowDefinition Height="20" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Text="{Binding PostOwner}" LineBreakMode="WordWrap" Font="Bold,16" />
<controls:CircleImage Grid.Row="0" Margin="10" BorderColor="white" BorderThickness="1" VerticalOptions="Start" HorizontalOptions="Start" Source="{Binding ProfileImage}" Aspect="AspectFit">
<controls:CircleImage.WidthRequest>
<OnPlatform x:TypeArguments="x:Double">
<On Platform="Android, iOS">65</On>
</OnPlatform>
</controls:CircleImage.WidthRequest>
<controls:CircleImage.HeightRequest>
<OnPlatform x:TypeArguments="x:Double">
<On Platform="Android, iOS">65</On>
</OnPlatform>
</controls:CircleImage.HeightRequest>
</controls:CircleImage>
<Label Grid.Row="1" Text="{Binding Post}" LineBreakMode="WordWrap" Font="Bold,16" />
<CarouselView x:Name="PostImages" Grid.Row="2" ItemsSource="{Binding PostImages}">
<CarouselView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding .}" Aspect="AspectFill" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
<!--<Image Grid.Row="2" Source="{Binding ImageURL}" Aspect="AspectFill" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />-->
<BoxView Grid.Row="3" BackgroundColor="black" HeightRequest="1" HorizontalOptions="FillAndExpand"/>
<StackLayout Grid.Row="4" Orientation="Horizontal" >
<Label Text="Likes: " LineBreakMode="NoWrap" Font="Bold,14" />
<Label Text="0" LineBreakMode="NoWrap" FontSize="14" />
</StackLayout>
<StackLayout Grid.Row="5" Orientation="Horizontal" >
<Label Text="Comments: " LineBreakMode="NoWrap" Font="Bold,14" HorizontalOptions="End" />
<Label Text="0" HorizontalOptions="End" LineBreakMode="NoWrap" FontSize="14" />
</StackLayout>
<!--<Label Grid.Row="2" Text="{Binding OwnerFullName}" LineBreakMode="NoWrap" FontSize="16" />-->
</Grid>
</Frame>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
In my code behind I have this
public Posts (GroupInfo ginfo)
{
InitializeComponent ();
GroupTitle.Text = ginfo.Title;
CurrentGroupInfo = ginfo;
GetDataPosts();
ItemsListView.RefreshCommand = new Command(() => {
GetDataPosts();
ItemsListView.IsRefreshing = false;
});
}
public void GetDataPosts()
{
try
{
string apikey = Application.Current.Properties["api"].ToString();
ItemsListView.ItemsSource = null;
posts.Clear();
if (RestController.GetMyPostData(ref posts, CurrentGroupInfo.Id.ToString(), apikey))
{
ItemsListView.ItemsSource = posts;
}
}
catch(Exception e)
{
Debug.WriteLine(e.Message);
}
}
now up to this point everything works and no errors but when the app goes to render the page I get a error
System.TypeInitializationException: The type initializer for 'Xamarin.Forms.ItemsView' threw an exception.
which I trace back to the Carousel View. When I comment out the Carousel View the it works. so I'm thinking I can't bind OR use the Carousel View in the way I thought?
The CarouselView used to be a plugin that has now become part of Xamarin.Forms effective with version 4. You can use an earlier XF version but you will need to get this plugin, add assembly references to your XAML and put initialization code in your platform specific projects.
Alternatively, you could upgrade to Xamarin.Forms 4
Even though you can see the Carousel View on Xamarin.Forms 3.6.0.344457, it only defines an interface there. There're no implementations and properties in the Carousel View Class.
You can only utilize it under Xamarin.Forms 4.0. As it is still a preview version now, there're some limitations. See my post here: https://stackoverflow.com/a/56235795/8354952 for more information.
I'm trying to create a FlexLayout in Xamarin.Forms that will allow me to have the left and right columns be a variable width, and have the center column (and its contents) fill the remaining space and be centered on the screen.
Here is my current code, and here is what it's producing. Notice that "CENTER TEXT" in blue is centered within its StackLayout, but the StackLayout is not centered on the screen since the left and right columns have different widths.
Is FlexLayout a good choice for this, or should I use Grid or something else? Ideally, each column will expand to fit its content, with the center column's content being centered on the screen.
Note that the contents of each column is dynamic, so the widths of the left and right columns is also dynamic.
Thank you!
Code:
<FlexLayout x:Name="titleBar"
MinimumHeightRequest="40"
Padding="10"
JustifyContent="SpaceBetween"
AlignItems="Center"
AlignContent="Center">
<StackLayout x:Name="leftActionButton"
VerticalOptions="Center"
BackgroundColor="Red"
Orientation="Horizontal">
<Image x:Name="leftActionImg"
Margin="0, 0, 5, 0"
HeightRequest="40"
VerticalOptions="Center" />
<Label x:Name="leftActionLabel"
VerticalOptions="Center" />
</StackLayout>
<StackLayout VerticalOptions="Center"
BackgroundColor="Blue"
FlexLayout.Grow="1"
FlexLayout.Shrink="0">
<Label x:Name="title"
HorizontalTextAlignment="Center"/>
</StackLayout>
<StackLayout x:Name="rightActionButton"
BackgroundColor="Yellow"
VerticalOptions="Center"
Orientation="Horizontal">
<Label x:Name="rightActionLabel"
VerticalOptions="Center"
HorizontalOptions="End"
HorizontalTextAlignment="End" />
<Image x:Name="rightActionImg"
HeightRequest="40"
VerticalOptions="Center"
HorizontalOptions="End" />
</StackLayout>
</FlexLayout>
Results:
I was struggling with the same problem recently. So I was investing a day to find a solution. The result is disillusioning and I wouldn't call it a proper solution. I'm posting my thoughts here, because I couldn't find anything similar on the net.
I created a component which is responsible for balancing all three columns: It subscribes to width changes of the left and right column and propagates the relative difference to the center column.
The center column takes the relative difference as correction by applying a padding.
MainPage: In the Resources part you see that I'm declaring an instance of ColumnBalancer. Later I subscribe Width changes to ColumnBalancer, so ColumnBalancer gets to known when the very left and very right column (content, actually) changes. The PaddingOffset binding is retrieved from the same ColumnBalancer instance whenever the Width values have changed.
<ContentPage
x:Class="App7863.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:cb="clr-namespace:ColumnBalancing"
mc:Ignorable="d">
<ContentPage.Resources>
<ResourceDictionary>
<cb:ColumnBalancer x:Key="ColumnBalancer" x:Name="ColumnBalancer" />
</ResourceDictionary>
</ContentPage.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Header -->
<Grid
Grid.Row="0"
Padding="10"
BackgroundColor="LightGray">
<Grid.RowDefinitions>
<RowDefinition Height="39" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- Navigate Back Button -->
<Label
Grid.Column="0"
Width="{Binding Source={x:Reference ColumnBalancer}, Path=ReferenceWidthLeft}"
Text="<"
FontSize="20"
BackgroundColor="Magenta"
WidthRequest="39"
HeightRequest="39"
VerticalOptions="CenterAndExpand"
VerticalTextAlignment="Center"
HorizontalOptions="CenterAndExpand"
HorizontalTextAlignment="Center" />
<!-- Page Title -->
<StackLayout
Grid.Column="1"
Margin="0"
Padding="{Binding Source={x:Reference ColumnBalancer}, Path=PaddingOffset}"
BackgroundColor="LightYellow"
Spacing="0">
<Label
Text="Center Title"
FontSize="20"
BackgroundColor="Magenta"
HeightRequest="39"
VerticalOptions="CenterAndExpand"
VerticalTextAlignment="Center"
HorizontalOptions="CenterAndExpand"
HorizontalTextAlignment="Center"
LineBreakMode="TailTruncation" />
</StackLayout>
<!-- Toolbar Items -->
<StackLayout
Grid.Column="2"
Width="{Binding Source={x:Reference ColumnBalancer}, Path=ReferenceWidthRight}"
Margin="0"
Padding="0"
BackgroundColor="LightGreen"
Orientation="Horizontal"
Spacing="6">
<Label
x:Name="ToolbarT1"
Text="T1"
FontSize="20"
BackgroundColor="Green"
WidthRequest="39"
HeightRequest="39"
VerticalOptions="CenterAndExpand"
VerticalTextAlignment="Center"
HorizontalOptions="CenterAndExpand"
HorizontalTextAlignment="Center"
IsVisible="False" />
<Label
x:Name="ToolbarT2"
Text="T2"
FontSize="20"
BackgroundColor="Green"
WidthRequest="39"
HeightRequest="39"
VerticalOptions="CenterAndExpand"
VerticalTextAlignment="Center"
HorizontalOptions="CenterAndExpand"
HorizontalTextAlignment="Center"
IsVisible="False" />
</StackLayout>
<Label
Grid.Row="2"
Grid.ColumnSpan="3"
Text="Subtitle with more info"
FontSize="20"
BackgroundColor="LightBlue"
HeightRequest="39"
VerticalOptions="CenterAndExpand"
VerticalTextAlignment="Center"
HorizontalOptions="StartAndExpand"
HorizontalTextAlignment="Start" />
</Grid>
<!-- Content -->
<Grid
Grid.Row="1"
Padding="40"
BackgroundColor="LightCoral">
<StackLayout BackgroundColor="LightBlue">
<Button Text="Toogle T1" Clicked="Button_ToogleT1" />
<Button Text="Toogle T2" Clicked="Button_ToogleT2" />
</StackLayout>
</Grid>
</Grid>
</ContentPage>
ColumnBalancer: Exposes a ReferenceWidthLeft and ReferenceWidthRight which take the Width values from the left resp. right column content. Whenever the ReferenceWidth* properties change, a new PaddingOffset is set.
public class ColumnBalancer : BindableObject
{
public static readonly BindableProperty PaddingOffsetProperty = BindableProperty.Create(
nameof(PaddingOffset),
typeof(Thickness),
typeof(ColumnBalancer),
default(Thickness),
BindingMode.OneWay);
public Thickness PaddingOffset
{
get => (Thickness)this.GetValue(PaddingOffsetProperty);
set => this.SetValue(PaddingOffsetProperty, value);
}
public static readonly BindableProperty ReferenceWidthRightProperty = BindableProperty.Create(
nameof(ReferenceWidthRight),
typeof(double),
typeof(ColumnBalancer),
default(double),
BindingMode.OneWayToSource,
null,
OnReferenceWidthRightPropertyChanged);
public double ReferenceWidthRight
{
get => (double)this.GetValue(ReferenceWidthRightProperty);
set => this.SetValue(ReferenceWidthRightProperty, value);
}
public static readonly BindableProperty ReferenceWidthLeftProperty = BindableProperty.Create(
nameof(ReferenceWidthLeft),
typeof(double),
typeof(ColumnBalancer),
default(double),
BindingMode.OneWayToSource,
null,
OnReferenceWidthLeftPropertyChanged);
public double ReferenceWidthLeft
{
get => (double)this.GetValue(ReferenceWidthLeftProperty);
set => this.SetValue(ReferenceWidthLeftProperty, value);
}
private static void OnReferenceWidthLeftPropertyChanged(BindableObject bindable, object oldvalue, object newvalue)
{
if (!(bindable is ColumnBalancer columnBalancer) || !(newvalue is double newLeftValue && newLeftValue >= 0))
{
return;
}
UpdatePaddingOffset(columnBalancer, newLeftValue, columnBalancer.ReferenceWidthRight);
}
private static void OnReferenceWidthRightPropertyChanged(BindableObject bindable, object oldvalue, object newvalue)
{
if (!(bindable is ColumnBalancer columnBalancer) || !(newvalue is double newRightValue && newRightValue >= 0))
{
return;
}
UpdatePaddingOffset(columnBalancer, columnBalancer.ReferenceWidthLeft, newRightValue);
}
private static void UpdatePaddingOffset(ColumnBalancer columnBalancer, double left, double right)
{
if (left < 0)
{
left = 0;
}
if (right < 0)
{
right = 0;
}
var relativePadding = Math.Abs(left - right);
if (right > left)
{
columnBalancer.PaddingOffset = new Thickness(relativePadding, 0, 0, 0);
}
else
{
columnBalancer.PaddingOffset = new Thickness(0, 0, relativePadding, 0);
}
}
}
I was able to get this to work by using a 2-column grid and overlaying the "center" column on top by using Grid.ColumnSpan="2".
I realize this has the potential for the content in the center to overlap the content on the left and right, but I'm OK with working around this limitation if that's the best I can do. Still welcome other, more robust suggestions, though!
<Grid x:Name="titleBar"
MinimumHeightRequest="40"
Padding="10"
HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackLayout x:Name="leftActionButton"
VerticalOptions="Center"
Orientation="Horizontal"
HorizontalOptions="Start"
Grid.Column="0">
<Image x:Name="leftActionImg"
Margin="0, 0, 5, 0"
HeightRequest="40"
VerticalOptions="Center" />
<Label x:Name="leftActionLabel"
VerticalOptions="Center" />
</StackLayout>
<StackLayout x:Name="rightActionButton"
VerticalOptions="Center"
HorizontalOptions="End"
Orientation="Horizontal"
Grid.Column="1">
<Label x:Name="rightActionLabel"
VerticalOptions="Center"
HorizontalOptions="End"
HorizontalTextAlignment="End" />
<Image x:Name="rightActionImg"
HeightRequest="40"
VerticalOptions="Center"
HorizontalOptions="End" />
</StackLayout>
<StackLayout VerticalOptions="Center"
HorizontalOptions="CenterAndExpand"
Grid.Column="0"
Grid.ColumnSpan="2">
<Label x:Name="title"
HorizontalTextAlignment="Center"/>
</StackLayout>
</Grid>