TabbedPage renders multiple times in Xamarin Forms using shell - forms

I have a problem using TabbedPages in my Xamarin.Forms mobile app (Shell).
When I navigate to a TabbedPage containing 3 tabs, the 3 tabs are crunched up and repeating themselves all down the page.
To replicate it I:
Created a standard Xamarin Forms Shell app in Visual Studio 2019 Version 16.4.5
Upgraded to Xamarin Forms 4.4.0.991640
Added a TabbedPage and changed the navigation of the About button to navigate to the TabbedPage instead.
Here is a photo of how it looks on my android phone
If I remember correctly it also happened when I deployed to my iPhone.
Update due to Jason's comment
All the code is automatically generated by Microsoft, my only interaction was to add an empty TabbedPage and change a line of code in AppShell.xaml.
(Note - while not relevant to this particular demo, I also got the same issue when navigating from a ListView in a ContentPage in my Xamarin.Forms app.)
Added TabbedPage1.xaml:
<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage 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"
mc:Ignorable="d"
x:Class="App1.Views.TabbedPage1">
<!--Pages can be added as references or inline-->
<ContentPage Title="Tab 1" />
<ContentPage Title="Tab 2" />
<ContentPage Title="Tab 3" />
</TabbedPage>
Added TabbedPage1.xaml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace App1.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class TabbedPage1 : TabbedPage
{
public TabbedPage1()
{
InitializeComponent();
}
}
}
Amended AppShell.xaml (all I did was change the line from DataTemplate local:AboutPage to DataTemplate local:TabbedPage1):
<?xml version="1.0" encoding="UTF-8"?>
<Shell 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"
mc:Ignorable="d"
xmlns:local="clr-namespace:App1.Views"
Title="App1"
x:Class="App1.AppShell">
<!--
Styles and Resources
-->
<Shell.Resources>
<ResourceDictionary>
<Color x:Key="NavigationPrimary">#2196F3</Color>
<Style x:Key="BaseStyle" TargetType="Element">
<Setter Property="Shell.BackgroundColor" Value="{StaticResource NavigationPrimary}" />
<Setter Property="Shell.ForegroundColor" Value="White" />
<Setter Property="Shell.TitleColor" Value="White" />
<Setter Property="Shell.DisabledColor" Value="#B4FFFFFF" />
<Setter Property="Shell.UnselectedColor" Value="#95FFFFFF" />
<Setter Property="Shell.TabBarBackgroundColor" Value="{StaticResource NavigationPrimary}" />
<Setter Property="Shell.TabBarForegroundColor" Value="White"/>
<Setter Property="Shell.TabBarUnselectedColor" Value="#95FFFFFF"/>
<Setter Property="Shell.TabBarTitleColor" Value="White"/>
</Style>
<Style TargetType="TabBar" BasedOn="{StaticResource BaseStyle}" />
</ResourceDictionary>
</Shell.Resources>
<!-- Your Pages -->
<TabBar>
<Tab Title="Browse" Icon="tab_feed.png">
<ShellContent ContentTemplate="{DataTemplate local:ItemsPage}" />
</Tab>
<Tab Title="About" Icon="tab_about.png">
<ShellContent ContentTemplate="{DataTemplate local:TabbedPage1}" />
</Tab>
</TabBar>
<!-- Optional Templates
// These may be provided inline as below or as separate classes.
// This header appears at the top of the Flyout.
<Shell.FlyoutHeaderTemplate>
<DataTemplate>
<Grid>ContentHere</Grid>
</DataTemplate>
</Shell.FlyoutHeaderTemplate>
// ItemTemplate is for ShellItems as displayed in a Flyout
<Shell.ItemTemplate>
<DataTemplate>
<ContentView>
Bindable Properties: Title, Icon
</ContentView>
</DataTemplate>
</Shell.ItemTemplate>
// MenuItemTemplate is for MenuItems as displayed in a Flyout
<Shell.MenuItemTemplate>
<DataTemplate>
<ContentView>
Bindable Properties: Text, Icon
</ContentView>
</DataTemplate>
</Shell.MenuItemTemplate>
-->
</Shell>

Related

Flyout Page not responding

I'm starting understanding .Net MAUI with an online video.
I'm trying to customize a page with 3 buttons, 1 for a counter, 1 for a second page and 1 for a flyoutpage.
Counter and second page are ok, flyout page doesn't display but force the App to exit.
My code for the button that calls the flyout page is this, located in the MainPage.xml.cs :
private void FlyClicked(object sender, EventArgs e)
{
Navigation.PushAsync(new Flyout1());
}
Can anybody explain me the reason of this ?
Many Thanks
According to your description, the Flyout1 should be a FlyoutPage. You can refer to the code below on how to create a FlyoutPage. I test it and it can display it.
Flyout1:
XAML:
<?xml version="1.0" encoding="utf-8" ?>
<FlyoutPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiAppDualScreen.Flyout1"
xmlns:local="clr-namespace:MauiAppDualScreen"
>
<FlyoutPage.Flyout>
<local:FlyoutMenuPage x:Name="flyoutPage" />
</FlyoutPage.Flyout>
<FlyoutPage.Detail>
<NavigationPage>
<x:Arguments>
<local:MainPage />
</x:Arguments>
</NavigationPage>
</FlyoutPage.Detail>
</FlyoutPage>
Code-behind:
public partial class Flyout1 : FlyoutPage
{
      public Flyout1()
      {
            InitializeComponent();
}
}
The following example shows the definition of the FlyoutMenuPage object, which is of type ContentPage:
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"
x:Class="MauiAppDualScreen.FlyoutMenuPage"
xmlns:local="clr-namespace:MauiAppDualScreen"
Title="FlyoutMenuPage">
<CollectionView x:Name="collectionView"
x:FieldModifier="public"
SelectionMode="Single">
<CollectionView.ItemsSource>
<x:Array Type="{x:Type local:FlyoutPageItem}">
<local:FlyoutPageItem Title="Contacts"
IconSource="dotnet_bot.png"
TargetType="{x:Type local:MainPage}" />
<local:FlyoutPageItem Title="TodoList"
IconSource="dotnet_bot.png"
TargetType="{x:Type local:MainPage}" />
<local:FlyoutPageItem Title="Reminders"
IconSource="dotnet_bot.png"
TargetType="{x:Type local:MainPage}" />
</x:Array>
</CollectionView.ItemsSource>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="5,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Source="{Binding IconSource}" />
<Label Grid.Column="1"
Margin="20,0"
Text="{Binding Title}"
FontSize="20"
FontAttributes="Bold"
VerticalOptions="Center" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ContentPage>
Code-behind:
public partial class FlyoutMenuPage : ContentPage
{
      public FlyoutMenuPage()
      {
            InitializeComponent();
      }
}
The flyout page consists of a CollectionView that's populated with data by setting its ItemsSource property to an array of FlyoutPageItem objects. The following example shows the definition of the FlyoutPageItem class:
public class FlyoutPageItem
{
public string Title { get; set; }
public string IconSource { get; set; }
public Type TargetType { get; set; }
}

How to change position of the app title in .NET MAUI?

I want to change the position of title to the middle or right side of the screen. I used the following code:
<Shell
x:Class="CostManagement.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:CostManagement"
Shell.FlyoutBehavior="Disabled"
FlowDirection="RightToLeft">
<ShellContent
Title="Main Page"
ContentTemplate="{DataTemplate local:MainPage}"
Route="MainPage" />
</Shell>
How can I change its position?
This can be customized by setting the Shell.FlyoutContent and use the CollectionView to define the appearance of the menu item like the title as you said. You can refer to the code sample below:
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="CostManagement.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:CostManagement"
FlyoutBackgroundColor="LightGray"
FlyoutBehavior="Flyout"
FlyoutWidth="400"
FlyoutHeight="400">
<Shell.FlyoutContent>
<CollectionView BindingContext="{x:Reference shell}" ItemsSource="{Binding FlyoutItems}" IsGrouped="True">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid ColumnDefinitions="40,*" Padding="10">
<Image Source="{Binding Icon}"></Image>
<Label Grid.Column="1" Text="{Binding Title}" TextColor="Black"></Label>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Shell.FlyoutContent>
</Shell>

How to reference converter in a ResourceDictionary file

I'm trying to create a resource dictionary file and reference a Value Converter. How can this be done?
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:converters="clr-namespace:CS.Runtime.Crew.Converters"
x:Class="CS.Runtime.Crew.Resources.CrewResourceDictionary" >
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<!--<converters:DateTimeToNullableDateTimeConverter x:Key="DateTimeToNullableDateTimeConverter" />-->
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
<DataTemplate x:Key="workGroupAttributesTemplate">
<Grid>
<controls:ExtendedDatePicker NullableDate="{Binding Attributes[DueDate], Converter={StaticResource DateTimeToNullableDateTimeConverter}}" Grid.Column="1" Grid.Row="4" />
</Grid>
</DataTemplate>
</ResourceDictionary>
First you add the class namespace
We assume class is Checker and checker is the namespace
Header
xmlns:checker="clr-namespace:Something.Checker;assembly=Something
Body
<checker:MySpecialValueConverter x:Key="MySpecialValue"/>
You can read more here
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/data-binding/converters#the-ivalueconverter-interface

Styling button in MVVM

I am writing a small WPF application using MVVM pattern.
I set some style resources for buttons into my main window and I would like them to apply to the buttons into the views. The problem is that some of the buttons are having a style with trigger. So I would like to inherit this style from the generic one
here is my main window code:
<Window.Resources>
<DataTemplate DataType="{x:Type vm:HomeViewModel}">
<views:HomeView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:DetailReportViewModel}">
<views:DetailReportView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:TransferViewModel}">
<views:TransferView/>
</DataTemplate>
<Style TargetType="{x:Type Button}">
<Setter Property="Margin" Value="5"/>
<Setter Property="MinWidth" Value="30"/>
<Setter Property="Foreground" Value="Red"/>
</Style>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="Margin" Value="5"/>
</Style>
</Window.Resources>
here is the button XAML into my view/usercontrol
<Button Content="Delete" Command="{Binding DeleteReportCommand}">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding Mode}">
<DataTrigger.Value>
<vm:Mode>Add</vm:Mode>
</DataTrigger.Value>
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
<DataTrigger Binding="{Binding Mode}">
<DataTrigger.Value>
<vm:Mode>Edit</vm:Mode>
</DataTrigger.Value>
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
I tried to used BasedOn="{StaticResource {x:Type Button} to inherit but it doesn't seems to work (see img)
I tried with a key name but static resource won't find the key name as it's not on the same view. And BasedOn is not accepting Dynamic resource.
Anything I am missing?
Thank you
You can put all the custom styles in a separate resource dictionary file and you can add it in usercontrol.resources.
Refer this: http://www.codeproject.com/Articles/35346/Using-a-Resource-Dictionary-in-WPF
Or you can put all those in app.xaml (Application.Resources).
Refer this: http://msdn.microsoft.com/en-us/library/system.windows.resourcedictionary.aspx

Datagrid not showing data even though its boudn

I have a problem with my MVVM Light implementation where I have my WPF Toolkit DataGrid and Data context bound to the correct object but no data is showing up. Can someone tell me what I'm doing wrong?
Here is my code:
MainViewModel.cs
public class MainViewModel : ViewModelBase
{
private static Logger logger = LogManager.GetCurrentClassLogger();
private C.Wsi.ClientSession privateSession;
private ObservableCollection<CashAccount> _cashaccounts;
public ObservableCollection<CashAccount> CashAccounts
{
get { return _cashaccounts; }
set
{
if (_cashaccounts.Equals(value))
{
return;
}
_cashaccounts = value;
RaisePropertyChanged("CashAccounts");
}
}
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel()
{
if (IsInDesignMode)
{
// Code runs in Blend --> create design time data.
}
else
{
_cashaccounts = new ObservableCollection<CashAccount>();
// Subscribe to CollectionChanged event
_cashaccounts.CollectionChanged += OnCashAccountListChanged;
logger.Info("----- Start -----");
// Code runs "for real"
Cs.Helper.Session session = new Session();
privateSession = session.getSession();
logger.Info("Private Session: " + privateSession.GetHashCode());
logger.Info("...Connected.....");
Cs.Helper.ResultSet results = new ResultSet();
PositionBean[] pos = results.getPositions(privateSession);
logger.Info("Positions returned: " + pos.Length);
SecurityBean[] secs = results.getSecurities(privateSession);
logger.Info("Securities returned: " + secs.Length);
ArrayBuilder ab = new ArrayBuilder(pos, secs);
CashAccount c = new CashAccount();
c.qtySod = 100.00;
c.name = "Hi";
c.account = "Acct1";
c.cashAmount = 67.00;
_cashaccounts.Add(c);
RaisePropertyChanged("CashAccounts");
//this._cashaccounts=ab.joinPositionSecurities();
}
}
void OnCashAccountListChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
}
////public override void Cleanup()
////{
//// // Clean up if needed
//// base.Cleanup();
////}
}
MainWindow.xaml
<Window x:Class="CreditSuisse.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:CreditSuisse.Helper"
xmlns:dg="http://schemas.microsoft.com/wpf/2008/toolkit"
mc:Ignorable="d"
Height="301"
Width="520"
Title="Credit Suisse - Custodial Cash Application"
DataContext="{Binding Path=Main, Source={StaticResource Locator}}">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Skins/MainSkin.xaml" />
</ResourceDictionary.MergedDictionaries>
<local:VisibilityConverter x:Key="VisibilityConverter" />
<!-- DataGrid Background -->
<LinearGradientBrush x:Key="BlueLightGradientBrush" StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="#FFEAF3FF"/>
<GradientStop Offset="0.654" Color="#FFC0DEFF"/>
<GradientStop Offset="1" Color="#FFC0D9FB"/>
</LinearGradientBrush>
<!-- DatGrid style -->
<Style TargetType="{x:Type dg:DataGrid}">
<Setter Property="Margin" Value="5" />
<Setter Property="Background" Value="{StaticResource BlueLightGradientBrush}" />
<Setter Property="BorderBrush" Value="#FFA6CCF2" />
<Setter Property="RowBackground" Value="White" />
<Setter Property="AlternatingRowBackground" Value="#FDFFD0" />
<Setter Property="HorizontalGridLinesBrush" Value="Transparent" />
<Setter Property="VerticalGridLinesBrush" Value="#FFD3D0" />
<Setter Property="RowHeaderWidth" Value="0" />
</Style>
<!-- Enable rows as drop targets -->
<Style TargetType="{x:Type dg:DataGridRow}">
<Setter Property="AllowDrop" Value="True" />
</Style>
</ResourceDictionary>
</Window.Resources>
<dg:DataGrid DataContext="{Binding MainViewModel}" ItemsSource="{Binding CashAccounts}">
Margin="5" AutoGenerateColumns="True" HorizontalScrollBarVisibility="False">
<dg:DataGrid.Columns>
<dg:DataGridTextColumn Binding="{Binding account}" Header="Account Code" />
<dg:DataGridTextColumn Binding="{Binding name}" Header="Security Name" />
<dg:DataGridTextColumn Binding="{Binding cashAmount}" Header="Quantity Start of Day" />
<dg:DataGridTextColumn Binding="{Binding price}" Header="Cash Delta (Price Delta)" />
<dg:DataGridTemplateColumn Header="Action">
<dg:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Get" Visibility="{Binding cashChanged, Converter={StaticResource VisibilityConverter}}" Background="Red" />
</DataTemplate>
</dg:DataGridTemplateColumn.CellTemplate>
</dg:DataGridTemplateColumn>
</dg:DataGrid.Columns>
</dg:DataGrid>
When you do DataContext="{Binding Path=Main, Source={StaticResource Locator}}" in your Window and after DataContext="{Binding MainViewModel}" in the Datagrid, WPF tries to bind to a property named MainViewModel on your MainViewModel class which will fail. You can confirm this by looking for the binding error in the Output window in VS.
Just remove DataContext="{Binding MainViewModel}" from the DataGrid and it should work.
EDIT:
There is an extra closing > at the end of the first line in your XAML:
<dg:DataGrid DataContext="{Binding MainViewModel}" ItemsSource="{Binding CashAccounts}">
Margin="5" AutoGenerateColumns="True" HorizontalScrollBarVisibility="False">
It should be:
<dg:DataGrid DataContext="{Binding MainViewModel}" ItemsSource="{Binding CashAccounts}"
Margin="5" AutoGenerateColumns="True" HorizontalScrollBarVisibility="Disabled">
Note: False is not a valid value for HorizontalScrollBarVisibility it supports Auto, Disabled, Hidden, Visible
But I don't know why WPF throws Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource instead for your original XAML instead of some more meaningful error.