How to show loading blocker view in windows phone? - windows-phone-7

I want to show loading blocker view while any HTTP request is going to server or when I am doing any async operations.
The main goal is sometimes we want to stop end user interaction with App UI until the operation complete.
In the Android world I would call the ProgressDialog, which causes the
screen to dim and the phone-specific spinner animation and whatever
message I want in the middle of the screen.
I know in windows phone we have option to indicate process in System tray
ProgressIndicator progress = new ProgressIndicator
{
IsVisible = true,
IsIndeterminate = true,
Text = "Connecting to server..." //TODO:Locale
};
SystemTray.SetProgressIndicator(this, progress);
But, I want to blocker UI interaction by adding view and my own loader animation in that view.
Can we call same view from whole application.
Thank you.

You can use a grid that cover all the page and control its Visibility by a property
<Grid Visibility="{Binding Path=YourGrid.LoadingVisibility,Source={StaticResource Locator}, UpdateSourceTrigger=Default,Mode=TwoWay}" x:Name="OverlayGrid" Grid.Row="0" Background="Transparent" Grid.Column="0" Grid.RowSpan="11" Grid.ColumnSpan="3" Style="{StaticResource PortraitGridStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="White" Opacity="0.4"></Border>
<ProgressBar IsIndeterminate="True" HorizontalAlignment="Center" Foreground="Black" VerticalAlignment="Center" Width="400" Height="10" />
</Grid>
This sample have the default animation in the Windows phone where 5 dots float around using progressbar control

Related

How to reliably get actual dimensions of a UWP Popup?

I have a UWP App which contains a Page which has 4 Popups defined on it. Each Popup is data-bound to a separate Boolean in the View Model. By manipulating the VM, I can make any of the 4 popus appear - only 1 at a time - maximum.
I would like to control where these Popups appear, so I've added "Opened" event handlers to each of them. The event handlers do the appropriate math to calculate Vertical & HorizontalOffset for the Popups.
This question, which was never answered is my problem as well. To explain it better, querying the popups ActualWidth/Height gives nonsense values. All of my popups are different sizes but all are landscape (width > height). I consistently get ActualWidth=310 & ActualHeight=779 for all of them.
By using the Popup's Child's dimensions (always a Grid) in the math, 2 of the 4 work consistently; the other 2 sometimes work, but usually not. EDIT: They fail because the Grid has no dimensions.
I'm assuming the Opened event is as late as possible to allow all Layout / Measures to occur. Short of hard-coding Heights & Widths on the Popups (one of which will have variable content), I've run out of stuff to try.
There's a lot of code, but they're virtually identical. This is one of the ones that works intermittently ...
<Popup x:Name="LoserTool"
IsOpen="{x:Bind vm.bLoseTool, Mode=OneWay}"
Opened="Popup_Opened"
>
<Grid x:Name="gLoserTool"
Background="{StaticResource TaipanHunter_Primary_Dark}"
BorderBrush="{StaticResource TaipanHunter_Primary_Light}"
BorderThickness="2"
Padding="20"
RowSpacing="10">
<Grid.RowDefinitions>
<RowDefinition Height="1.5*" />
<RowDefinition Height="5*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.2*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="0.2*" />
</Grid.ColumnDefinitions>
<TextBlock Text="Oh No!"
Grid.Column="1"
Grid.Row="0"
Style="{StaticResource TaipanHunter_Title}"
/>
<TextBlock Text="Your tool broke!"
Grid.Column="1"
Grid.Row="1"
Style="{StaticResource Text_LightText}"
/>
<Button Content="Play Again"
Click="StartNewGame"
Grid.Column="1"
Grid.Row="2"
HorizontalAlignment="Center"
Style="{StaticResource Button_Base}"
/>
</Grid>
</Popup>

How to set the Position of a MediaElement upon button click?

I'm working on a Xamarin Forms application. Right now I'm trying to implement custom video controls into my MediaElement but I'm failing to do so, and googling isn't helping much.
Basic overview, I have a MediaElement playing a video, and I have two buttons on each side of the video that I would like the user to be able to press and rewind or fast forward 5 seconds. The buttons recognize being clicked, but do not do what I want them to, and I'm not sure what I am doing wrong. Here is my code:
Page.xaml
...
<Grid BackgroundColor="#E5EBEE">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="150"/>
</Grid.ColumnDefinitions>
<MediaElement x:Name="LessonVideo"
Source="ms-appx:///vid_IntroDemo.mp4"
ShowsPlaybackControls="False"
IsLooping="True"
Aspect="AspectFill"
AutoPlay="True"
KeepScreenOn="True"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
Grid.ColumnSpan="3"
/>
<BoxView Opacity="0.0" BackgroundColor="#00C2FF"/>
<Button x:Name="Back" BackgroundColor="Yellow" Grid.Column="0" Opacity="0.2" Clicked="RewindVideo"></Button>
<Button x:Name="Forward" BackgroundColor="Red" Grid.Column="2" Opacity="0.2"></Button>
</Grid>
Page.xaml.cs
...
private void RewindVideo(object sender, EventArgs e)
{
if (LessonVideo.CanSeek)
{
LessonVideo.Position = TimeSpan.FromSeconds(LessonVideo.Position.TotalSeconds - 5);
}
}
I've experimented with stopping and playing the video, but nothing seems to be working. Help me out and point me in the right direction how to solve this. Thank you in advance.

How to create a table with vertically sticky header and horizontally sticky first column using Xamarin Forms?

When displaying tabular data, I think that in some cases having an always visible header row and an always visible first column can really improve the readability and the overall usability of a table, especially if there is a lot of data in the table. The problem occurs when the table has to support both horizontal and vertical scrolling. A good example of such a table can be found from the NBA application when viewing box score of a past game. Here's an example image from the NBA Android application:
Example table from NBA mobile application
As you can clearly see from the image the header row is horizontally aligned with the actual table data and the first column is vertically aligned with the table data. I don't know whether or not it's an involuntary or a voluntary decision to prevent scrolling both horizontally and vertically with the same touch motion but that's a minor detail I don't care about.
I don't know how to implement this using Xamarin Forms. I am not interested in a closed source / paid solution since I would like to actually learn how to accomplish this by myself. I do realize that I most likely have to use custom renderers for both Android and IOS. My current idea is that I have an absolute layout where I have the following elements:
The first cell (it's stationary and the only stationary thing)
Rest of the header row inside a horizontal scrollview
First column inside a listview/stacklayout + vertical scrollview
The actual table data inside a listview + horizontal scrollview / stacklayout + horizontal and vertical scrollview
With this setup I would capture the touch event and send it to the other listviews/scrollviews, thus synchronizing the scrolling. In fact I can easily achieve the synchronized scrolling with the first column and the actual table data by setting the table data inside the same vertical scrollview as the first column. But I don't know how to synchronize the horizontal scrolling to the header row and I do believe that this can't be accomplished by clever component structure. I have tested only on Android so far that I can capture the touch event in a scrollview custom renderer's OnTouchEvent -method but I don't know how I could send this to the header row scrollview from the custom renderer.
Here is a draft XAML illustrating my approach.
<AbsoluteLayout xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
HorizontalOptions="FillAndExpand">
<ScrollView
Orientation="Horizontal"
x:Name="HeaderScrollView"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<!-- Skip first column, leave it empty for stationary cell -->
<Label Text="Column 1" Grid.Row="0" Grid.Column="1" />
<Label Text="Column 2" Grid.Row="0" Grid.Column="2" />
<Label Text="Column 3" Grid.Row="0" Grid.Column="3" />
<Label Text="Column 4" Grid.Row="0" Grid.Column="4" />
</Grid>
</ScrollView>
<ScrollView
x:Name="FirstColumnScrollView"
Orientation="Vertical"
AbsoluteLayout.LayoutBounds="0,50,1,1"
AbsoluteLayout.LayoutFlags="SizeProportional"
BackgroundColor="Aqua">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackLayout
Grid.Column="0"
Grid.Row="0"
BindableLayout.ItemsSource="{Binding DataSource}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<Label Text="{Binding Column1}" Grid.Row="0" Grid.Column="0" />
</Grid>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
<ScrollView
x:Name="TableDataScrollView"
Grid.Column="1"
Grid.Row="0"
Orientation="Horizontal">
<StackLayout
BindableLayout.ItemsSource="{Binding DataSource}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Label Text="{Binding Column2}" Grid.Row="0" Grid.Column="0" />
<Label Text="{Binding Column3}" Grid.Row="0" Grid.Column="1" />
<Label Text="{Binding Column4}" Grid.Row="0" Grid.Column="2" />
<Label Text="{Binding Column5}" Grid.Row="0" Grid.Column="3" />
</Grid>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</ScrollView>
</Grid>
</ScrollView>
<Label Text="First Column" BackgroundColor="White" AbsoluteLayout.LayoutBounds="0,0,200,50" />
</AbsoluteLayout>
As you can see the problem is that horizontal scrolling events between HeaderScrollView and TableDataScrollView are not shared and I don't know how to accomplish this in the best way possible or at all.
I do appreciate all the help and feedback with this!
What you are looking for is a DataGrid component with Frozen row and Frozen column feature. There are some third party components that would meet your requirements.
Syncfusion, Telerik and Infragistics DataGrids have the features you are looking for. Refer below links.
https://www.syncfusion.com/xamarin-ui-controls/xamarin-datagrid
https://www.telerik.com/xamarin-ui/datagrid
https://www.infragistics.com/products/xamarin/grids-and-lists/data-grid
There are few open-source DataGrid available as well. But not sure whether they have the row and column pinning features. Check the below links.
https://github.com/akgulebubekir/Xamarin.Forms.DataGrid
https://www.nuget.org/packages/Xamarin.Forms.DataGrid/
For open source, you could use Zumero DataGrid for Xamarin.Forms. It supports scrolling, both horizontal and vertical, optional top frozen header row, optional left frozen column and so on. You could download the sample code form the link below.
Zumero DataGrid for Xamarin.Forms: https://github.com/zumero/DataGrid/tree/8caf4895e2cc4362da3dbdd4735b5c6eb1d2dec4
For the sample code, if you get the error below, run as admin would be okay.
Build action 'EmbeddedResource' is not supported by one or more of the project's targets
Thanks for the help with this #Harikrishnan and #Wendy Zang - MSFT ! The Zumero DataGrid inspired me to do the motion event handling differently from the usual motion event handling flow. I basically created the following custom renderer for the AbsoluteLayout
using Android.Content;
using Android.Views;
using Test.Droid;
using Test.Views;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using View = Android.Views.View;
[assembly: ExportRenderer(typeof(StatisticsTable), typeof(StatisticsTableRenderer))]
namespace Test.Droid
{
public class StatisticsTableRenderer : ViewRenderer
{
private View _headerScrollView;
private View _tableScrollView;
private float _startX;
public StatisticsTableRenderer(Context context) : base(context)
{
}
public override bool OnInterceptTouchEvent(MotionEvent ev)
{
if (_headerScrollView == null || _tableScrollView == null)
{
// Completely dependant on the structure of XAML
_headerScrollView = GetChildAt(0);
_tableScrollView = GetChildAt(1);
}
return true;
}
public override bool OnTouchEvent(MotionEvent ev)
{
if (ev.Action == MotionEventActions.Down)
{
_startX = ev.GetX();
}
var headerScroll = false;
if (_startX > _headerScrollView.GetX())
{
headerScroll = _headerScrollView.DispatchTouchEvent(ev);
}
var tableScroll = _tableScrollView.DispatchTouchEvent(ev);
return headerScroll || tableScroll;
}
}
}
As you can see I always intercept the motion event and then manually dispatch it to the children. However that was not enough. I had to prevent HeaderScrollView from scrolling when the motion event didn't start inside of it because the TableDataScrollView wouldn't scroll if the motion event wasn't started inside of it. I also had to create custom renderers for all scrollviews in this table. TableDataScrollView and HeaderScrollView were using the same custom renderer. The only thing that custom renderer implemented was OnInterceptTouchEvent like this:
public override bool OnInterceptTouchEvent(MotionEvent ev)
{
return false;
}
I am not quite sure why this is necessary but it seems to have done the trick for me. I suppose that sometimes the HeaderScrollView would intercept the motion event and this caused the header to scroll without scrolling of the table data.
The vertical scrollview aka FirstColumnScrollView in the question's XAML had to implement motion event handling differently because it is the parent of the TableDataScrollView and we are now handling motion events in a top-to-bottom manner instead of the default Android way of bottom-to-top. This caused issues where FirstColumnScrollView would simply handle the motion event and not pass it to TableDataScrollView which would then lead to the header and actual table data to be out of sync with each other. This is why I added the following custom renderer for it
using Android.Content;
using Android.Views;
using Test.Droid;
using Test.Views;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using View = Android.Views.View;
[assembly: ExportRenderer(typeof(ChildFirstScrollView), typeof(ChildFirstScrollViewRenderer))]
namespace Test.Droid
{
public class ChildFirstScrollViewRenderer : ScrollViewRenderer
{
private View _childView;
public ChildFirstScrollViewRenderer(Context context) : base(context)
{
}
public override bool DispatchTouchEvent(MotionEvent e)
{
if (_childView == null)
{
_childView = GetChildAt(0);
}
_childView.DispatchTouchEvent(e);
return base.DispatchTouchEvent(e);
}
public override bool OnInterceptTouchEvent(MotionEvent ev)
{
return true;
}
}
}
In this ScrollView we always intercept/handle the motion event and we always send it to the child ScrollView first before handling the motion event.
I also had to do some minor adjustments to the XAML shown in the question. I set the starting X of HeaderScrollView to the width of the first column so it doesn't actually go under the static header of the first column. However this caused issues because I was unable to use width of the AbsoluteLayout (Why is it so hard in XAML?) to calculate the correct width for the HeaderScrollView. Now the width was set in a way that a part of the HeaderScrollView will always be outside of the viewport causing the last header to be never shown. So I added a "PaddingColumn" to the header grid with a width equal to the first column. I also had to add a "PaddingRow" to the FirstColumnScrollView grid for the same reason.
One other thing I had to do was to set the spacing of the grid inside FirstColumnScrollView to 0. Without that, there was this small gap from where you could start motion events that would only scroll the header and not the table data.
This is only the Android solution at the moment but I'll come back with the iOS one if I can accomplish it.

Adding labels on both ends of a progress bar in Xamarin Forms

I have a progress bar in Xamarin Forms defined in my XAML.
Actually I want to add labels beneath the progress that shows the minimum and maximum value of the progress bar as shown in the image below:
My XAML code:
<StackLayout Orientation="Vertical" Margin="5">
<Frame Padding="10"
BackgroundColor="White"
HeightRequest="80">
<Frame.Content>
<Label Text="%" HorizontalTextAlignment="End" FontSize="Small"/>
<ProgressBar x:Name="myProgressBar" WidthRequest="100"
HeightRequest="15" VerticalOptions="Center" HorizontalOptions="Center" Progress="0.2"/>
</Frame.Content>
</Frame>
</StackLayout>
Can someone please help me to achieve this in Xamarin Forms ? Also, how can I add a gradient color like in the image ?
For the text, you would probably want to use labels positioned under the progressbar. I'd recommend a grid with two rows.
As for the gradient, unfortunately the xamarin forms progress bar doesn't support this out of the box. You can either create a custom renderer for each platform that draws the gradient, or consider a third party control like Syncfusion's (https://www.syncfusion.com/products/xamarin/progress-bar)
You can make a custom Xamarin Forms control.
The content could be something like that:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5* />
<ColumnDefinition Width="0.5* />
</Grid.ColumnDefinition>
<Image x:Name="gradientImage" Grid.Row="0" Grid.ColumnSpan="2" Margin="10,10,10,0" />
<Frame x:Name="progressFrame" Grid.Row="0" Width="{Binding Progress}" HorizontalOption="End" BackgroundColor="Gray" ... />
<!-- Labels -->
<Label x:Name="startLbl" Grid.Row="1" Grid.Column="0" Text="{Binding startLabel}" HorizontalOption="Start" />
<Label x:Name="endLbl" Grid.Row="1" Grid.Column="1" Text="{Binding endLabel}" HorizontalOption="End" />
</Grid>
For the gradient progress bar, instead of CustomRenderers you can use an image.
this image will be the full width gradient bar
over this image, like a MASK, there is a frame. You have to compute the frame width depending on the progress value. ==> It will 'make appear" the gradient image smotthly when progress will increase.
Hope you understand the concept :)
Then in the code behind (in your ViewModel ?) manage the start/end label values and the computation of the "progress" value... I presume you will have to make a Binding Converter for: "progress" ==> "bar Width"...
Tell me if it's clear
Wanted to comment on above answer from #KFactory but don't have permission yet.
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5* />
<ColumnDefinition Width="0.5* />
</Grid.ColumnDefinition>
Has a few typos. missing end quotes and s on closing tag. Should be
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="0.5*" />
</Grid.ColumnDefinitions>

2 TextBlocks in ScrollView.

I'm developing a page, that needs 1 article in bold and second normal.
Texts can be very long, so I need a scroll view of the page. Example of the page:
And here is the code of my Grid.Row that is Content:
<ScrollViewer Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Width="auto" Height="auto" Grid.Column="0" Grid.Row="0" Name="ArticleContent" />
</Grid>
</ScrollViewer>
When I run this code - nothing apears on the screen
Nothing is being displayed you have not set the text of the textblocks.
You can set text manually by Text = "fdjhldjfgldkgd"
or you can use binding Text ="{Binding asd}".
One more thing you should also set the foreground of the textblock as black or any desired color.
If your text length is too much and you want to wrap the the text then you will have to use TextWrapping = Wrap
hope this might help..
Set your TextBlock's Text property to the content that you want in there
<TextBlock Text="Hello"/>
If it needs to be bound to a data backend this could be done either in code behind or through wpf
<TextBlock Text="{Binding x}"/>
or
Binding B = new Binding("x");
BindingOperations.SetBinding(ArticleContent, TextBlock.TextProperty, B);
Hope this helps?

Resources