How to change background of TabbedPage's invidually in Xamarin.Forms? - background

I tried to change BarBackgroundColor property but only first case of switch is working and setting color purple. CurrentPageChanged event is firing but not changing background color. Additionally how to change invidially background of single tab background.
In my public partial class Tabbed : TabbedPage
public void changeColorOfTabBar(int index)
{
switch (index)
{
case 0:
BarBackgroundColor = Color.FromHex(Constants.evrensel_purple);
break;
case 1:
BarBackgroundColor = Color.FromHex(Constants.evrensel_green);
break;
case 2:
BarBackgroundColor = Color.FromHex(Constants.evrensel_blue);
break;
default:
BarBackgroundColor = Color.FromHex(Constants.color_blue);
break;
}
}
public void createTabs(LoginResponse response)
{
Children.Add(new HomeTab(response) { Title = "Home", Icon = "home.png" });
Children.Add(new TimesheetTab(response) { Title = "Timesheet", Icon = "timesheet.png" });
Children.Add(new MyLeavesTab(response) { Title = "My Leaves", Icon = "leave.png", });
}
public Tabbed (LoginResponse response,LoggedInfo info)
{
InitializeComponent();
Title = "Welcome, " + _serviceEmployee.getEmployeeByUserId(response.userid).fullnameReplaced;
CurrentPageChanged += (sender, args) =>
{
var index = Children.IndexOf(CurrentPage);
changeColorOfTabBar(index);
};
createTabs(response);
res = response;
}

Related

Subscribe to DisplayAlert in Xamarin.Forms

I'd like to get notified whenever DisplayAlert is called somewhere in my app. The Xamarin.Forms source code suggests to use the MessagingCenter, since it is using it to send a message within DisplayAlert():
MessagingCenter.Send(this, AlertSignalName, args);
But I haven't been able to receive anything, yet. This is one of the lines I tried so far:
MessagingCenter.Subscribe<Page>(this, Page.AlertSignalName, arg => {
Console.WriteLine("Message received: " + arg);
});
Is this the right direction? Or do you have an alternative solution? I'd even consider some hacky reflection-based approach, since I need it for testing purposes only.
This works for me:
MessagingCenter.Subscribe<Page, Xamarin.Forms.Internals.AlertArguments>(this, Page.AlertSignalName, (obj, obj1) => {
int aa = 0;
});
But it is raised when DisplayAlert is displayed. (I think it's correct...)
This is my page:
using System;
using Xamarin.Forms;
namespace Test
{
public class MyPage : ContentPage
{
public MyPage()
{
Button b = new Button {Text = "Press" };
b.Clicked += async (object sender, EventArgs e) => {
await DisplayAlert("Attention", "AAA", "Ok");
MessagingCenter.Send<MyPage>(this, "AAA");
};
Content = new StackLayout
{
Children = {
new Label { Text = "Hello ContentPage" },
b
}
};
MessagingCenter.Subscribe<MyPage>(this, "AAA", (obj) => {
int aa = 0;
});
MessagingCenter.Subscribe<Page, Xamarin.Forms.Internals.AlertArguments>(this, Page.AlertSignalName, (obj, obj1) => {
int aa = 0;
});
}
}
}
In Xamarin source test code (namespace Xamarin.Forms.Core.UnitTests), it's used in a strongly typed way like that:
[Test]
public void DisplayAlert ()
{
var page = new ContentPage ();
AlertArguments args = null;
MessagingCenter.Subscribe (this, Page.AlertSignalName, (Page sender, AlertArguments e) => args = e);
var task = page.DisplayAlert ("Title", "Message", "Accept", "Cancel");
Assert.AreEqual ("Title", args.Title);
Assert.AreEqual ("Message", args.Message);
Assert.AreEqual ("Accept", args.Accept);
Assert.AreEqual ("Cancel", args.Cancel);
bool completed = false;
var continueTask = task.ContinueWith (t => completed = true);
args.SetResult (true);
continueTask.Wait ();
Assert.True (completed);
}
So this should do it:
MessagingCenter.Subscribe(this, Page.AlertSignalName, (Page sender, AlertArguments args) =>
{
Console.WriteLine("Message received: " + args.Message);
});

(UWP) How to activate the "Taskbar Miniplayer" like in Groove

I use the BackgroundMediaPlayer for my App to play Audio in the Background. Now i see these buttons:
How can i activate them?
In order to make the media controls from the taskbar to work, you need to load and configure the SystemMediaTransportControls from the foreground application AND the background task. If you are doing it only from the background task, the controls will be displayed but they will remain disabled.
In your foreground application, you should have the following code:
var smtc = SystemMediaTransportControls.GetForCurrentView();
smtc.ButtonPressed += smtc_ButtonPressed;
smtc.PropertyChanged += smtc_PropertyChanged;
smtc.IsEnabled = true;
smtc.IsPauseEnabled = true;
smtc.IsPlayEnabled = true;
smtc.IsNextEnabled = true;
smtc.IsPreviousEnabled = true;
And in the background task, you should have :
smtc = BackgroundMediaPlayer.Current.SystemMediaTransportControls;
smtc.ButtonPressed += smtc_ButtonPressed;
smtc.PropertyChanged += smtc_PropertyChanged;
smtc.IsEnabled = true;
smtc.IsPauseEnabled = true;
smtc.IsPlayEnabled = true;
smtc.IsNextEnabled = true;
smtc.IsPreviousEnabled = true;
Beware that the API to get the control instance is not the same:
SystemMediaTransportControls.GetForCurrentView()
in the foreground app and BackgroundMediaPlayer.Current.SystemMediaTransportControls in the background task.
You will have to support the button pressed event in the two (foreground + background)
That's System Media Transport Controls and you should add code to handle click event.
Here is official sample:
public MainPage()
{
this.InitializeComponent();
// Hook up app to system transport controls.
systemMediaControls = SystemMediaTransportControls.GetForCurrentView();
systemMediaControls.ButtonPressed += SystemControls_ButtonPressed;
// Register to handle the following system transpot control buttons.
systemMediaControls.IsPlayEnabled = true;
systemMediaControls.IsPauseEnabled = true;
}
async void SystemControls_ButtonPressed(SystemMediaTransportControls sender,
SystemMediaTransportControlsButtonPressedEventArgs args)
{
switch (args.Button)
{
case SystemMediaTransportControlsButton.Play:
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
mediaElement.Play();
});
break;
case SystemMediaTransportControlsButton.Pause:
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
mediaElement.Pause();
});
break;
default:
break;
}
}

GridView: Get Index on Drop Event

How do I get the index or position where a GridViewItem is being dropped inside the OnDrop event of the GridView? As I have read around that it is possible with GridView.ItemContainerGenerator.ContainerFromItem(item) but for me ItemContainerGenerator is null.
This is my current code:
void gridMain_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
{
var item = e.Items.First();
var source = sender;
e.Data.Properties.Add("item", item);
e.Data.Properties.Add("source", sender);
}
void gridMain_Drop(object sender, DragEventArgs e)
{
var item = e.Data.Properties.Where(p => p.Key == "item").Single();
object source;
e.Data.Properties.TryGetValue("source", out source);
var s = ((GridView)source).ItemContainerGenerator.ContainerFromItem(item);
}
Any hint or suggestion will be really helpful.
Use GetPosition method of DragEventArgs to find the position where item was dropped and then calculate the actual index, see code snippet below for the handler. Similar question was asked here using this MSDN example as an answer (Scenario 3).
private void GridView_Drop(object sender, DragEventArgs e)
{
GridView view = sender as GridView;
// Get your data
var item = e.Data.Properties.Where(p => p.Key == "item").Single();
//Find the position where item will be dropped in the gridview
Point pos = e.GetPosition(view.ItemsPanelRoot);
//Get the size of one of the list items
GridViewItem gvi = (GridViewItem)view.ContainerFromIndex(0);
double itemHeight = gvi.ActualHeight + gvi.Margin.Top + gvi.Margin.Bottom;
//Determine the index of the item from the item position (assumed all items are the same size)
int index = Math.Min(view.Items.Count - 1, (int)(pos.Y / itemHeight));
// Call your viewmodel with the index and your data.
}
EDIT: Please, consider this as just a prototype. I tried it and it has worked properly, but you may revise it according to your scenario (tweak delay timeout, differentiate more TaskCompletionSource at once, etc.).
The idea is to start a task after Remove action to check whether the item was only removed, or reordered.
private async void observableCollection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
{
object removedItem = e.OldItems[0];
var reorderTask = NoticeReorderAsync(removedItem);
try
{
var task = await Task.WhenAny(reorderTask, Task.Delay(100));
if (reorderTask == task)
{
// removedItem was in fact reordered
Debug.WriteLine("reordered");
}
else
{
TryCancelReorder();
// removedItem was really removed
Debug.WriteLine("removedItem");
}
}
catch (TaskCanceledException ex)
{
Debug.WriteLine("removedItem (from exception)");
}
finally
{
tcs = null;
}
}
else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
object addedItem = e.NewItems[0];
bool added = NoticeAdd(addedItem);
if (added)
{
// addedItem was just added, not reordered
Debug.WriteLine("added");
}
}
}
TaskCompletionSource<object> tcs;
private void TryCancelReorder()
{
if (tcs != null)
{
tcs.TrySetCanceled();
tcs = null;
}
}
private Task NoticeReorderAsync(object removed)
{
TryCancelReorder();
tcs = new TaskCompletionSource<object>(removed);
return tcs.Task;
}
private bool NoticeAdd(object added)
{
if (tcs != null)
{
try
{
if (object.Equals(tcs.Task.AsyncState, added))
{
tcs.TrySetResult(added);
return false;
}
else
{
tcs.TrySetCanceled();
return true;
}
}
finally
{
tcs = null;
}
}
return true;
}

How to add a list of UIelement in Windows Phone

I want to create a page with dynamic control in windows phone.
While doing this I also want to show a progress bar
Below is my code
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
progressstackPanel.Visibility = Visibility.Visible;//progress bar
formScreen = this;
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
if (!isfst)
{
DrawScreen();
}
else
{
//xTitlePanel is only stack panel in my xaml with vertical orientation
xTitlePanel.UpdateLayout();
}
isfst = true;
progressstackPanel.Visibility = Visibility.Collapsed;
});
}
//Code of DrawScreen which is adding control to my stack panels
private void DrawScreen()
{
if (frm_getset.ChildList != null)
{
String[] arr = frm_getset.ChildList.Split(',');
xTitlePanel.Children.Clear();
PrepareControls prepcontrol = new PrepareControls();
foreach (AttributeGetSet a in _Attribute)
{
//this will return a stackpanel containing
// button/textbox etc.depending on a
StackPanel sp = prepcontrol.getControl(i, a.Label, a, formScreen);
try
{
xTitlePanel.Children.Add(sp);
///Here I get a eception only one control is added first one
/// for anyone it is getting a exception Argument
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
i += 1;
}
The system is adding only one control and when ever it try to execute xTitlePanel.Children.Add(sp); it will get an exception.
I solved the problem ,"xTitlePanel" is a StackPanel I created in my XAML. I found you can not add more that one element from Dispatcher to a control crated on xaml. Like that. so I have to create local stack and add controls to the that local stack panel then and after complete I add the local stack panel to xTitlePanel. NOW my code looks like below
filteredList = new List<FormGetSet>();
if (frm_getset.ChildList != null)
{
String[] arr = frm_getset.ChildList.Split(',');
foreach (String x in arr)
{
filteredList.Add(_template.list_fromgetset.Where(p => p.FormID.Contains(x.Trim())).ToList()[0]);
}
}
xTbox_FormNameHeader.Text = frm_getset.NAME;
_Attribute = new List<AttributeGetSet>();
_Attribute = frm_getset.list_attributegetset;
xTitlePanel.Children.Clear();
StackPanel spPanel = new StackPanel();
spPanel.Orientation = System.Windows.Controls.Orientation.Vertical;
spPanel.Background = new SolidColorBrush(Colors.Transparent);
//xTitlePanel.Children.Add(PrepareControls.getControl(1, "LABEL", "16"));
int i = 1;
// List<AttributeGetSet> _Attribute2 = new List<AttributeGetSet>();
foreach (AttributeGetSet a in _Attribute)
{
PrepareControls prepcontrol = new PrepareControls();
StackPanel sp= prepcontrol.getControl(i, a.Label, a, this);
try
{
spPanel.Children.Add(sp);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
//xTitlePanel.Background = new SolidColorBrush(Colors.White);
//_Attribute2.Add(a);
i += 1;
}
xTitlePanel.Children.Add(spPanel);

Create Application bar dynamically

I want to create Application Bar dynamically in Windows Phone 8. I have used the following code to create application bar in appbar.cs file
class AppBar
{
public AppBar()
{
ApplicationBar appbar;
this.appbar = new ApplicationBar();
this.appbar.IsVisible = true;
this.appbar.Opacity = 1;
this.appbar.Mode = ApplicationBarMode.Minimized;
ApplicationBarIconButton appButon = new ApplicationBarIconButton();
appButon.IconUri = new Uri("/images/show.png", UriKind.Relative);
appButon.Text = "Show";
this.appbar.Buttons.Add(appButon);
appButon.Click += appButon_Click;
}
}
void appButon_Click(object sender, EventArgs e)
{
}
}
If i have created the instance of AppBar class, then all the methods called but i unable to see the application bar. I have given request to create the appbar from webview. From the javainterface i have created the instance of application bar with the given text and icon. How to show this in the web page.
I have solved the my Application bar issue. Added my application bar with parent element(PhoneApplicationPage).
class AppBar
{
public AppBar()
{
ApplicationBar appbar;
PhoneApplicationPage parentpage = (Application.Current.RootVisual as ContentControl).Content as PhoneApplicationPage;
parentpage.ApplicationBar = new ApplicationBar();
appbar = parentpage.ApplicationBar;
appbar.IsVisible = true;
appbar.Opacity = 1;
appbar.Mode = ApplicationBarMode.Minimized;
ApplicationBarIconButton appButon = new ApplicationBarIconButton();
appButon.IconUri = new Uri("/images/show.png", UriKind.Relative);
appButon.Text = "Show";
appbar.Buttons.Add(appButon);
appButon.Click += appButon_Click;
}
}
void appButon_Click(object sender, EventArgs e)
{
}
}