Reputation: 33
I'm struggling with Xamarin frames taking extra space when "showing/hiding" content into them. I've seen several related posts and implemented content templates which didn't solve it.
Basically I have a detailed view containing a Syncfusion ListView
. Withing such ListView
I'm rendering cards that should be dynamic, some of them contains a chart, some others not, cards contain different info based on category.
Here is my DetailCard
implementation:
public class DetailCard : BaseCard
{
public bool ChartDataVisible { get; set; }
public string detailsList;
public DetailCard()
{
ChartDataVisible = false;
}
}
public class BaseCard : INotifyPropertyChanged
{
#region Field
private IReadOnlyCollection<ChartModel> chartData;
#endregion
#region Events
/// <summary>
/// The declaration of the property changed event.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
#endregion
#region Property
/// <summary>
/// Gets or sets the property that has been displays the Category.
/// </summary>
public string Category { get; set; }
/// <summary>
/// Gets or sets the property that has been displays the Category value.
/// </summary>
public string CategoryValue { get; set; }
/// <summary>
/// Gets or sets the property that has been displays the Category percentage.
/// </summary>
public string CategoryPercentage { get; set; }
/// <summary>
/// Gets or sets the property that has been bound with SfChart Control, which displays the health care data visualization.
/// </summary>
public IReadOnlyCollection<ChartModel> ChartData
{
get
{
return this.chartData;
}
set
{
if (this.chartData == value)
{
return;
}
this.chartData = value;
this.OnPropertyChanged("ChartData");
}
}
/// <summary>
/// Gets or sets the property that has been displays the background gradient start.
/// </summary>
public string BackgroundGradientStart { get; set; }
/// <summary>
/// Gets or sets the property that has been displays the background gradient end.
/// </summary>
public string BackgroundGradientEnd { get; set; }
#endregion
#region Methods
/// <summary>
/// The PropertyChanged event occurs when changing the value of property.
/// </summary>
/// <param name="property">Property name</param>
protected void OnPropertyChanged(string property)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
#endregion
}
Here's my ChartView control template (Notice this will be visible or not with a boolean Binding from my Model):
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:chart="clr-namespace:Syncfusion.SfChart.XForms;assembly=Syncfusion.SfChart.XForms"
x:Class="SmartFarm.Shared.Views.Templates.ChartView"
IsVisible="{TemplateBinding BindingContext.ChartDataVisible}" >
<ContentPresenter/>
<chart:SfChart
Margin="0,11,0,0"
BackgroundColor="Transparent"
HeightRequest="{OnIdiom Phone=44,
Desktop=80,
Tablet=80}"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<chart:SfChart.PrimaryAxis>
<chart:DateTimeAxis
IsVisible="True"
RangePadding="None"
ShowMajorGridLines="False" />
</chart:SfChart.PrimaryAxis>
<chart:SfChart.SecondaryAxis>
<chart:NumericalAxis IsVisible="True" ShowMajorGridLines="False" />
</chart:SfChart.SecondaryAxis>
<chart:SfChart.Series>
<chart:SplineSeries
ItemsSource="{TemplateBinding BindingContext.ChartData , Mode=TwoWay}"
StrokeWidth="2"
XBindingPath="DateTimeXValue"
YBindingPath="YValue"
Color="{DynamicResource Deep-Purple}" />
</chart:SfChart.Series>
</chart:SfChart>
</StackLayout>
Here is my list view into a Details ContentPage:
<listView:SfListView
x:Name="listViewCards"
AutoFitMode="Height"
IsScrollingEnabled="False"
ItemSize="74"
ItemsSource="{Binding CardItems}"
SelectionMode="None"
TapCommand="{Binding ItemTappedCommand}">
<listView:SfListView.ItemTemplate>
<DataTemplate>
<svg:CustomShadowFrame
x:Name="shadowFrame"
Margin="16,8"
Padding="0"
BackgroundColor="{DynamicResource GrayShadowColor}"
BorderWidth="0"
CornerRadius="4"
HasShadow="True"
HorizontalOptions="CenterAndExpand"
Radius="4"
WidthRequest="{OnIdiom Phone=343,
Default=736}">
<Grid
Padding="16"
RowDefinitions="Auto, *"
RowSpacing="5">
<!-- Category -->
<Label
HeightRequest="24"
HorizontalOptions="Start"
Style="{StaticResource TitleLabelStyle}"
Text="{Binding CategoryValue}" />
<!-- Category Value -->
<Label
Grid.Row="1"
FontSize="15"
HeightRequest="{Binding Category}"
HorizontalOptions="FillAndExpand"
HorizontalTextAlignment="Start"
Style="{StaticResource DescriptionLabelStyle}"
Text="{Binding Category}" />
<ContentView
x:Name="chartView"
Grid.Row="2"
ControlTemplate="{StaticResource ChartView}" >
</ContentView>
</Grid>
</svg:CustomShadowFrame>
</DataTemplate>
</listView:SfListView.ItemTemplate>
Here the results
I'm still not dealing on how to resolve this, but now I'm thinking in removing the content view from each frame if my chart flag is false, how can I achieve this from code behind? I can't get a Frame list from my list view like this:
protected override void OnAppearing()
{
base.OnAppearing();
var listView = listViewCards as Syncfusion.ListView.XForms.SfListView;
var itemSource = listView.ItemsSource as ObservableCollection<DetailCard>;
var itemTemplate = listView.ItemTemplate;
//I need a mechanism here to loop into all Frames from list view and remove the content view code
}
Upvotes: 0
Views: 303
Reputation: 49
We have checked the reported query from our end. We would like to inform you that the empty space in the view is a contentview. We suggest to you to bind the IsVisible property to the ContentView instead of StackLayout to overcome the reported scenario.
Code snippet:
<ContentView
x:Name="chartView"
IsVisible = "{Binding ChartDataVisible}"
Grid.Row="2"
ControlTemplate="{StaticResource ChartView}" >
</ContentView>
We have checked the reported query from our side. You cannot get the elements from the ItemTemplate directly. However you can handle the ItemTemplate with different layout like you’re your chart flag is false you can use another template with the help of DataTemplateSelector in a SfListView.
You can also refer to the following UG Documentation link for your reference. UG Link:https://help.syncfusion.com/xamarin/listview/viewappearance#data-template-selector
Or you can stick with the above solution with IsVisible property. Based on chart flag you can architect your UI.
Upvotes: 0
Reputation: 8174
As per your requirement mentioned first of all you need to update the Grid definition like this:
<Grid
Padding="16"
RowDefinitions="Auto, *, Auto"
RowSpacing="5">
Make the third row as Auto
which contains the ChartView, after this control the Visibility of <ContenView>
using a bool property based on availability of data to be displayed in Chart like this:
<ContentView
x:Name="chartView"
Grid.Row="2"
IsVisible="{Binding IsChartDataAvailable}"
ControlTemplate="{StaticResource ChartView}"/>
You need to have this IsChartDataAvailable
property of type bool in your model class of ItemSource
=> CardItems
Upvotes: 1
Reputation: 33
I ended up adding row definition to each Frame row and binding the row size, this is probably not the best way to do it but worked for me:
public class DetailCard : BaseCard
{
public bool ChartDataVisible { get; set; }
public GridLength RowSize { get; set; }
public string DetailsList { get; set; }
public DetailCard()
{
ChartDataVisible = false;
RowSize = new GridLength(0);
}
}
<Grid
Padding="16"
RowSpacing="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="{Binding RowSize}"/>
</Grid.RowDefinitions>
<!-- Category
.
.
.
-->
<!-- Category Value
.
.
.
-->
<ContentView
x:Name="chartView"
IsVisible="{Binding ChartDataVisible}"
Grid.Row="2"
ControlTemplate="{StaticResource ChartView}" >
</ContentView>
</Grid>
Upvotes: 0
Reputation: 11105
Have you tried setting SfListView.AutoFitMode
to DynamicHeight
? DynamicHeight
will change the cell's height dynamically if a control in that cell changes size or is hidden from view. It may be sizing your cell with the chart's initial height and then once the binding kicks in, the height changes but the cell does not update.
You may also want to set the RowHeight on the Grid's Column that contains the Graph to Auto so that row will automatically collapse.
Syncfusion Docs:
Upvotes: 0