Global MediaElement that continues playing after navigating to other page - windows-runtime

I am using a MediaElement to play music in my metro app.
I want the Music keeps playing even if I navigate to another Page.
In the following Thread that question was asked also:
http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/241ba3b4-3e2a-4f9b-a704-87c7b1be7988/
I did what JimMan suggested
1) In App.xaml.cs Changed the control template of the root frame to include the MediaElement
var rootFrame = new Frame();
rootFrame.Style = Resources["RootFrameStyle"] as Style;
rootFrame.Navigate(typeof(HomePage), MainViewModel.Instance);
Window.Current.Content = rootFrame;
Window.Current.Activate();
2) In Styles.xaml add
<Style x:Key="RootFrameStyle" TargetType="Frame">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Frame">
<Grid>
<MediaElement x:Name="MediaPlayer" AudioCategory="BackgroundCapableMedia" AutoPlay="True" />
<ContentPresenter />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
3) To Access the MediaElement on the Page navigated to:
DendencyObject rootGrid = VisualTreeHelper.GetChild(Window.Current.Content, 0);
MediaElement rootMediaElement = (MediaElement)VisualTreeHelper.GetChild(rootGrid, 0);
But VisualTreeHelper.GetChild(Window.Current.Content, 0); always returns null, even if I try to access the MediaElemt on the Root page.
I builded a little example Project to demonstrate.
Sample Project
Any Ideas ?
Thanks in advance !
Best regards
Fabian

It's possible your Navigated handler where you try to get the visual tree child gets called before the visual tree is fully loaded (added to visual tree). You could try moving your code to the Loaded event handler.
EDIT*
I confirmed my theory by making the following change:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
DependencyObject rootGrid = VisualTreeHelper.GetChild(Window.Current.Content, 0);
MediaElement rootMediaElement = (MediaElement)VisualTreeHelper.GetChild(rootGrid, 0);
}
}

Related

Show map from VM

I try to show on a ContentPage an ObservableCollection of type Activity (class I created). This one contains a Title (string) and a Map (xamarin.forms.maps) :
Map myMap = new Map();
myMap.IsShowingUser = true;
activity.Map = myMap;
obActivities.Add(activity);
Here is my XAML :
<ListView x:Name="listActivities" HorizontalOptions="StartAndExpand" VerticalOptions="FillAndExpand"
SeparatorColor="LightGray" SeparatorVisibility="Default" HasUnevenRows="True"
ItemsSource="{Binding obActivities}" CachingStrategy="RecycleElement"
ItemSelected="ListActivities_ItemSelected" SelectedItem="{Binding selectedActivity,Mode=TwoWay}" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" Padding="5" VerticalOptions="FillAndExpand">
<ContentView Content="{Binding Map}"></ContentView>
<Label Text="{Binding Title}" FontSize="12" TextColor="Gray"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The Title is well displayed.
I tried a lot of things (may be everything I can ^^) to show the Map but nothing works. The last thing I tried before this post... <ContentView Content="{Binding Map}"></ContentView> but no result.
EDIT :
I also tried to add my map control onto the XAML like :
<map:Map>
<map:Map.MapElements>
<map:Polyline>
<map:Polyline.Geopath>
</map:Polyline.Geopath>
</map:Polyline>
</map:Map.MapElements>
</map:Map>
But I don't know where I have to add the polyline's position from my VM.
May be you can help me to find the right XAML ...
I recommend managing a collection of UI elements (here, Maps) from inside the View or Page. I would move all the ViewModel code into the Page's code behind .xaml.cs file. There is still a "model" for each item ("Activity"), but no longer a ViewModel corresponding to the Page itself.
NOTE: This is an "impure" approach, as Activity is a mixture of model and UI information. Nevertheless, it is simpler code to do it this way. So I won't attempt to show a "pure" solution. In a simple case, the complications of doing so outweigh the "maintenance" benefit [easier to make changes without causing a bug] of keeping view and model separate. If this causes some problem later, refactor at that time.
Then BindingContext becomes the page itself:
public MyPage() {
InitializeComponent();
InitMyData();
BindingContext = this;
}
public ObservableCollection<Activity> obActivities { get; set; } = new ObservableCollection<Activity>();
void InitMyData() {
Map myMap = new Map();
myMap.IsShowingUser = true;
activity.Map = myMap;
obActivities.Add(activity);
}
The Map may lack a height when it is created. StackLayout may have given it "0" height by default. Specify some height:
Map myMap = new Map();
myApp.HeightRequest = 100;
Having a "hardcoded" height (e.g. 100) also helps speed up the initial layout of the page.

How can i access control name of MapControl inside a Hub Windows Phone 8.1

I want create a mapcontrol inside the Hub control, but everytime i tryed access from CS file,i can't find the name! Here is the code!
<HubSection Header="Rotas e Mapas" Foreground="White">
<DataTemplate>
<Grid>
<Maps:MapControl
x:Name="MapControl1"
MapServiceToken="ubgfhnhduyekheddjd"/>
</Grid>
</DataTemplate>
</HubSection>
Your problem is that your map control is inside a DataTemplate. It exists in the Visual Tree and not the Logical tree. I'd recommend you to read this article on the subject - How to access a named control inside a XAML DataTemplate (using CSharp)
You can handle the Loaded event of the MapControl control, and inside it cast the sender parameter to MapControl and assign it to a page variable.
<HubSection Header="Map">
<HubSection.ContentTemplate>
<DataTemplate>
<Maps:MapControl Loaded="MapControl_Loaded" ...
public sealed partial class HubPage : Page
{
private MapControl map;
...
private async void MapControl_Loaded(object sender, RoutedEventArgs e)
{
map = (MapControl)sender;
map.Style = MapStyle.Aerial;
...

Is it possible to temporarily postpane displaying an AppBarButton's affiliated Flyout?

I've got a Flyout embedded within an AppBarButton like so:
<AppBarButton x:Name="appbarbtnOpenPhotosets" Icon="OpenFile" Label="Open Existing Photoset[s]" AutomationProperties.Name="Open File" Tapped="appbarbtnOpenPhotosets_Tapped" >
<Button.Flyout>
. . .
</Button.Flyout>
</AppBarButton>
I want to, under certain circumstances, first present the user with an opportunity to rename a file prior to seeing the Flyout. I tried seeing if that would work like this:
async private void appbarbtnOpenPhotosets_Tapped(object sender, TappedRoutedEventArgs args)
{
// Want to conditionally postpone the operation
bool myBucketsGotAHoleInIt = PhotraxUtils.GetLocalSetting(CAINT_BUY_NO_BEER);
if (myBucketsGotAHoleInIt)
{
MessageDialog dlgDone = new MessageDialog("Can you see me now?");
await dlgDone.ShowAsync();
args.Handled = false; // <= adding this made no difference
}
}
This works, in that I see the "Can you see me now?" dialog, but that prevents the Flyout from flying out. A Flyout that doesn't fly out is no more useful than a flying squirrel or fish that doesn't motate through the air.
So how can I temporarily suppress my flyout but then call it forth? The Flyout does not have an Open() method...Is there some other way to invoke it?
Flyouts attached to Buttons open automatically when you click the control.
If you don't want it to open automatically, you need to attach it to another control.
Example taken from official documentation:
<!-- Flyout declared inline on a FrameworkElement -->
<TextBlock>
<FlyoutBase.AttachedFlyout>
<Flyout>
<!-- Flyout content -->
</Flyout>
</FlyoutBase.AttachedFlyout>
</TextBlock>
Then you can show the Flyout whenever you want, calling FlayoutBase.ShowAttachedFlyout() and passing the FrameworkElement casted value of your control.
FlyoutBase.ShowAttachedFlyout(frameworkElement);
So, in your case:
async private void appbarbtnOpenPhotosets_Tapped(object sender, TappedRoutedEventArgs args)
{
// Want to conditionally postpone the operation
bool myBucketsGotAHoleInIt = PhotraxUtils.GetLocalSetting(CAINT_BUY_NO_BEER);
if (myBucketsGotAHoleInIt)
{
MessageDialog dlgDone = new MessageDialog("Can you see me now?");
await dlgDone.ShowAsync();
// New code
FlyoutBase.ShowAttachedFlyout((FrameworkElement)sender);
}
}
If you can't change the control, you should able to use the code I posted with Buttoninstead of TextBlock. I'm not sure about this, but you can try.

Metro/Windows Store App: Relative Image Source Binding does not work?

I'm trying to create an ImageToggleButton for my WinRT project that changes it's image in respect to its IsChecked property.
In the designer of Visual Studio 2012 and Visual Studio Express for Windows 8 the ToggleButton behaves as expected, but during run time the image does not get displayed.
Any ideas?
XAML:
<Page.Resources>
<local:BooleanImageConverter x:Name="BoolImgConverter"/>
</Page.Resources>
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<ToggleButton HorizontalAlignment="Left" Height="200" Margin="260,205,0,0" VerticalAlignment="Top" Width="833" Background="Yellow">
<Image Source="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Parent.IsChecked, Converter={StaticResource BoolImgConverter}, ConverterParameter=Assets/chkMusic}"/>
</ToggleButton>
</Grid>
CodeBehind:
public class BooleanImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string culture)
{
bool state = (bool)value;
string baseName = (string)parameter;
return string.Format("{0}_{1}checked.png", baseName, state ? "" : "un");
}
public object ConvertBack(object value, Type targetType, object parameter, string culture)
{
return null;
}
}
Code description:
I'd put an Image control into the ToggleButton and bind the image source to the IsChecked property of the containing (parent) ToggleButton using a converter that decorates the given ConverterParameter according IsChecked to provide the string to reference the desired image file.
Sure I could do this in code behind, but I would prefer to do it in XAML as much as possible.
At the moment I'm also not after building a ControlTemplate and I would have tried RelativeSource FindAncestor and other suggestions of this forum, but these dids not seem to work in Windows Store Apps (or am I wrong?).
I'd appreciate any suggestions.
Thanks
(BTW: I tried to add windows-store-app as tag to this post, but could not create this new tag - would someone else do this)
Parent has never worked as you think it would. There are a couple of ways to accomplish what you need.
The first is to keep the RelativeSource binding but remove the Path to IsChecked. This will pass the control to the converter. In it you can get the parent using the VisualTreeHelper.
The second is to name your ToggleButton and bind to it using ElementName binding
<ToggleButton x:Name="MusicToggle" HorizontalAlignment="Left" Height="200" Margin="260,207,-793,-207" VerticalAlignment="Top" Width="833" Background="Yellow">
<Image Source="{Binding IsChecked, ElementName=MusicToggle, Converter={StaticResource BoolToImage}, ConverterParameter=Assets/chkMusic}"/>

Custom Event from Item Renderer not detected by a class

I am trying to dispatch a custom event from an item renderer(which is a child of the Main application file / root).
Code in Main.mxml:
<s:List id="movieGrid"itemRenderer="views.MovieRenderer" dataProvider="{new ArrayCollection()}">
</s:List>
<s:Group width="100%" height="100%" bottom="60">
<views:DetailedViewInfo id="detailed" includeIn="MoviePage" />
</s:Group>
Renderer (something clicked):
MyEventDispatcher.Dispatcher.dispatchEvent(new MovieClickEvent(MovieClickEvent.CLICKED, data));
DetailedViewInfo (creation complete):
MyEventDispatcher.Dispatcher.addEventListener(MovieClickEvent.CLICKED, clickHandler);
MyEventDispatcher:
package events
{
import flash.events.EventDispatcher;
public class MyEventDispatcher
{
public static var Dispatcher:EventDispatcher = new EventDispatcher();
}
}
Event:
package events
{
import flash.events.Event;
public class MovieClickEvent extends Event
{
public function MovieClickEvent(type:String, theMovieData:Object, bubbles:Boolean=true, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
this._result = theMovieData;
}
public function get result():Object
{
return this._result;
}
override public function clone():Event
{
return new MovieClickEvent(type, result, bubbles, cancelable)
}
public static const CLICKED:String = "MovieClickEvent.CLICKED";
private var _result:Object;
}
}
I am able to listen for the event successfully in the Main.mxml but I also need to detect it in a SkinnableContainer - "DetailedViewInfo" that is also a child of Main.mxml:
It his possible at all? I tried importing all related events / classes and same for declarations. It does not work even if I comment out the event listener in Main.mxml. I tried adding a declaration to the item renderer in DetailedViewInfo but that crashes the application with no understandable error.
Could someone explain to me how this should be done? I am using custom events all over the place in my application and hadn't had this happen before. Any help highly appreciated!
It would seem you're adding the event listener after the event was dispatched. I see you have an includeIn statement there: this means the DetailedViewInfo component will not be immediately created, but only when the MoviePage state is entered. The event may be dispatched before the component is created and the event listener attached.
The quick fix for this issue, is to not use includeIn, but set the component's visibility according to the current state:
<views:DetailedViewInfo id="detailed" visible="false" includeInLayout="false"
visible.MoviePage="true" includeInLayout.MoviePage="true" />
However, you may want to review your architecture if you need to resort to this. Unfortunately I can't tell you much more than that, since I don't know your current architecture.