I am having one Windows phone game, built using Silverlight. In this game, I want to add TapJoy. I have downloaded their latest SDK and follow all their steps to intigrate the it within my app.
In the game, I am using silverlight as a main frame work and Global Media Element to play contious Background Music. I am using
(Microsoft.Xna.Framework.Media) (Microsoft.Xna.Framework) namespace.
Using them, I use following methods to play contious background sound.
DispatcherTimer and FrameworkDispatcher.Update
Now, when I click tap joy button to open their offers, they load fine; however, when I open the video within the offer, they show us following error “Video cannot be played, please try again.”
Based on some research and study, I tried few things and found that,
a) I need to set Media Element and DispatcherTimer is to null.
b) The application is sent in background (deactivated) and then I open it again (activated), the video is coming fine. I checked and found that Media Element and DispatcherTimer were set to null properly.
But if I follow step one only, and do not send the app in background, the media element and dispatcherTimer are not set to null.
Can anyone please help me and answer me following
a) Am I doing anythign wroing with this?
b) Can I do anything so that when tap joy button is clicked, my application is sent to background automatically since this can solve the issue.
c) I am using gc.collect() after setting value to null but still it is not getting destroyed.
Thanks in advance,
David Jacob.
I'm trying to follow along with what you've said. I personally would've set it up differently, but I'll get to that later.
I have a setup that is similar to your description, and it works with Tapjoy's Videos.
Firstly, you mentioned that it was a Silverlight game, so I created a new Windows Phone Application project under the Silverlight For Windows Phone template, in VS 2010.
Setup Dispatcher:
I added the following class to my project (typically called XNAFrameworkDispatcherService.cs from this msdn example: http://msdn.microsoft.com/en-us/library/ff842408.aspx)
public class XNAFrameworkDispatcherService : IApplicationService
{
private DispatcherTimer frameworkDispatcherTimer;
public XNAFrameworkDispatcherService()
{
this.frameworkDispatcherTimer = new DispatcherTimer();
this.frameworkDispatcherTimer.Interval = TimeSpan.FromTicks(333333);
this.frameworkDispatcherTimer.Tick += frameworkDispatcherTimer_Tick;
FrameworkDispatcher.Update();
}
void frameworkDispatcherTimer_Tick(object sender, EventArgs e)
{
FrameworkDispatcher.Update();
}
void IApplicationService.StartService(ApplicationServiceContext context)
{
this.frameworkDispatcherTimer.Start();
}
void IApplicationService.StopService()
{
this.frameworkDispatcherTimer.Stop();
}
}
In order to start this service, make sure you've added it to your App.xaml.
Add an attribute to your Application element that points to your namespace, something like this:
xmlns:s="clr-namespace:WindowsPhoneApplication;assembly=WindowsPhoneApplication">
Then within your block add the following:
<s:XNAFrameworkDispatcherService />
Play Music:
Now about playing a looping music file.
In the MainPage.xaml.cs, I've setup a Microsoft.Xna.Framework.Media.Song to loop when the page is navigated to, using the Microsoft.Xna.Framework.Media.MediaPlayer.
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
Tapjoy.TapjoyConnect.Instance.RequestTapjoyConnect("your-app-id", "your-secret-key");
try
{
Song song = Song.FromUri("example", new Uri("/example.wma", UriKind.Relative));
MediaPlayer.IsRepeating = true;
MediaPlayer.Play(song);
}
catch (Exception)
{
System.Diagnostics.Debug.WriteLine("Can't load sound");
}
}
I also set it to stop playing music, when the page is navigated away from.
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
MediaPlayer.Stop();
}
I then created a button to launch the Tapjoy Offer wall.
private void button1_Click(object sender, RoutedEventArgs e)
{
Tapjoy.TapjoyConnect.Instance.ShowOffers();
}
Summary:
What happens now, is when your Application starts up, it launches the XNAFrameworkDispatcherService that ticks at approximately 30fps. This will dispatch messages that are in the XNA Framework Queue for you. This is only needed in silverlight applications that are using audio/media services from XNA.
When the MainPage is navigated to, you ping Tapjoy with the Connect call, and you load up your Song to loop.
Normal gameplay can progress now, and when the Show Offers button is clicked, Tapjoy will navigate away from your page, causing on navigated from event to fire, and the MediaPlayer will stop your song.
Ideas for your game:
You might want to consider creating a new project and using the "Windows Phone Silverlight and XNA Application" option. VS2010 will create a blank project with a Content manager already setup, so you can use sounds and images with the XNA pipeline, which I've found to be easier.
Good luck, and remember that Tapjoy provides support for these issues as well. Just email them at support#tapjoy.com, or use the Tapjoy Developer group at: https://groups.google.com/group/tapjoy-developer?hl=en
Related
I am trying to optimize the loading times for my WPF prism application. The loading is basically a loop of using reflection to create instances of UI elements and then adding them to the main window (the shell) in a tab control.
Since we are limited to using a single thread to create all the objects, what would be the optimal way to speed up loading / create a better user experience?
These are the options I have so far:
Use lazy loading. Only load the tab when the user first clicks on it. But that would have a 4-5 second delay opening the first time as it gets initialized on demand.
Cache all the reflection calls. I actually did that, but it did not speed anything up at all. Most of the time occurs during the rendering of the controls...
?
Any suggestions would be greatly appreciated for this tricky problem.
You're pretty much stuck as you can only load objects on the main thread, so I don't think you'll make it load any faster.
What you can do is distract the user: I have an animated splash screen that take about 10 seconds to work its way through the animation sequence. This serves a number of purposes:
It shows the user motion - so they have a visual cue that something is going on
It distracts them and fills the space taken by the initial load
To ensure smooth animation you need to create a second dispatcher. Here's how I do it:
public class AppEntry : Application
{
private static ManualResetEvent _resetSplashCreated;
internal static Thread SplashThread { get; set; }
internal static SplashWindow SplashWindow { get; set; }
private static void ShowSplash()
{
SplashWindow = new SplashWindow();
SplashWindow.Show();
_resetSplashCreated.Set();
Dispatcher.Run();
}
[STAThread]
public static void Main()
{
_resetSplashCreated = new ManualResetEvent(false);
SplashThread = new Thread(ShowSplash);
SplashThread.SetApartmentState(ApartmentState.STA);
SplashThread.IsBackground = true;
SplashThread.Name = "Splash Screen";
SplashThread.Start();
_resetSplashCreated.WaitOne();
var app = new App();
app.DispatcherUnhandledException += new DispatcherUnhandledExceptionEventHandler(app_DispatcherUnhandledException);
app.InitializeComponent();
app.Run();
}
static void app_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
// MessageBox.Show(e.Exception.StackTrace);
}
}
I set the AppEntry class as my Startup Object in the Project Properties/Application tab.
I close my splash screen at the end of my OnStartup method in App:
AppEntry.SplashWindow.Dispatcher.BeginInvoke(DispatcherPriority.Background,
new Action(() => AppEntry.SplashWindow.Close()));
Is this faster? No
Does the user think it's faster? Yes
Sometimes, if you can't give them speed, you can give them activity. It's a nice placebo.
As you mentioned, You cannot Multithread if your objects are DependencyObjects. Kent Boogart discusses this. That's why you must leverage INotifyPropertyChanged and do POCO objects to hold your data. That way you can multithread to obtain the data and then bind these to your UI. Another drawback of using DependencyObjects is that you're tying your application too much to the WPF framework (DependencyObject being a class defined in the System.Windows namespace in a WPF assembly (don't remember if PresentationCore or PresentationFramework)). If refactoring is not an option, you will have to consider a solution like the one LastCoder proposed. Be aware that you will be able to do very little multithreading (if any at all), therefore your application is not going to be very responsive all the time.
I would implement a timer that loads a few controls or tabs every tick (iteration). The timer will run on the same thread as the UI (control messages for it will be queued up on the Windows Message Loop). Once all of the work is done you can kill the timer.
The timer interval and the number of controls to load per tick will boil down to use-testing; try something like 100ms and 2 controls a tick that will give you ~20 controls a second, so if you had 10 tabs with 15 controls each it would take ~8seconds, but the UI shouldn't lock up as bad.
The best answer to speeding up the loading is to simply hide the container while the visual tree is being constructed.
This prevents the screen from constantly needing to update itself.
When all the elements have been added to the visual tree, then setting the container visibility to visible renders the tab container once.
We also implemented some simple lazy-rendering to the tab control items.
Net result: loading times from 2 minutes down to about 20 seconds.
When my MainPage loads in my Windows Phone 7 application, it triggers a popup splash screen that includes a progress bar and a graphic in a usercontrol. After displaying the spash screen I do some work in a BackgroundWorker thread to load some resources while the spash displays. When the loading is done I dismiss the popup. This technique is well documented on WindowsPhoneGeek.
I noticed today that while this is working flawlessly when running in debug under Visual Studio, if I run the same build directly without the debugger connected, the splash screen animation and progress bar never appear and the DoWork() thread takes at least twice as long to execute the same operations. I can see that the MainPage constructor gets called as well as OnNavigatedTo, but the popup still does't display and the default jpg splash image remains on the screen, until the worker thread completes. Then the popup displays for < 1 second and the mainpage displays. Again, this all works flawlessly when debugging through VS 2010.
This is all in the Emulator, I don't have a device yet. I just noticed this today, and coincidently(?) I just updated the environment to 7.1 last night.
// Constructor
public MainPage()
{
InitializeComponent();
IDictionary<string, object> state = Microsoft.Phone.Shell.PhoneApplicationService.Current.State;
if (!state.ContainsKey(STATE_WAS_LOADED))
{
state[STATE_WAS_LOADED] = "LOADED";
this.LayoutRoot.Visibility = System.Windows.Visibility.Collapsed;
_popup = new Popup();
_popup.Child = new NPGSplash();
System.Diagnostics.Debug.WriteLine("{0}: Displaying Splash Popup", DateTime.Now.ToString("ss.ffff"));
_popup.IsOpen = true;
// Asynchronously load the biggest dataset
StartLoadingData();
}
}
private void StartLoadingData()
{
_worker = new BackgroundWorker();
_worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_worker_RunWorkerCompleted);
_worker.RunWorkerAsync();
}
void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.Dispatcher.BeginInvoke(() =>
{
System.Diagnostics.Debug.WriteLine("{0}: Splash RunWorkerCompleted", DateTime.Now.ToString("ss.ffff"));
this.LayoutRoot.Visibility = System.Windows.Visibility.Visible;
this._popup.IsOpen = false;
});
}
EDIT:
I ended up buying a device on ebay this week to ensure that I don't release an app where I can't confirm that it works properly. I can confirm that whatever the problem is, it does NOT occur when running the application on the device. Good news. Still, I can't explain what appears to be an approximately 3-5 second pause in my application after the consrtuctor is called. I even changed my logic in the constructor to set a System.Windows.Threading.DispatcherTimer to fire in 100ms to kick off my logic. When this code executes, the constructor completes, but the timer doesn't tick for 3-5 seconds. Very odd, and only in the simulator when not attached to the debugger.
The problem here would appear to be that you are never attaching the Popup control to the visual tree. To be honest, I've got no idea why this would work with the debugger attached either, but I'm going off what I can interpret from your code.
What I think you need to do is to add the Popup control as an element in the XAML for MainPage so that it is attached to the visual tree.
One other thing I'd say is that it's perhaps worth moving all the data loading code out of the constructor and into either an override for OnNavigatedTo or a handler for the Loaded event. Generally speaking, it's best to keep constructors and short and simple as possible (and yes I appreciate that you're using a background worker to load the data).
I believe this is just a problem for me, due to my lack of programming ability. I am currently exploring transitions between page navigation with Windows Phone apps. I was originally using storyboards, and completed event handlers to have my pages animate on and off screen. These leads to the a problem when you want to navigate to many pages from one page, using the same transition.
So I have started looking at OnNavigatedTo, and OnNavigatingFrom events and while it is working nicely for OnNavigatedTo, the later just wont work. It seems the Microsoft.Phone.Navigation assembly does not contain OnNavigatingFrom, and referencing System.Windows.Navigation, compiles ok, but I cant get pages to animate off upon navigation.
I have a button on my Page2, which I want to go back to my MainPage (after I over-rided the back key with a message box for testing). I have transitions made on the page, and I have this as the event handler code...
private void btnP2_BackToP1Clicked(object sender, System.Windows.RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
}
With this code for the OnNavigatedTo and OnNavigatingFrom events...
protected override void OnNavigatedTo(PhoneNavigationEventArgs e)
{
PageTransition_In.Begin();
}
// //
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
PageTransition_Out.Begin();
base.OnNavigatingFrom(e);
}
I have the feeling that OnNavigatingFrom may not(yet) be supported for Windows Phone Apps. OnNavigatedFrom is part of Microsoft.Phone.Navigation, but it only performs actions once the page is no longer active, which is too late to perform any animation effects.
I believe that you need to add an event that captures the transition completion. Check out the demo that Microsoft provides for a list view application.
The approach you are taking is not quite correct. Instead it is better to alter the page frame to know how to do transitions between pages. You can see a good examples of this on a Channel 9 vid or on Avi Pilosof's blog.
Example:
<ControlTemplate x:Key="TransitioningFrame" TargetType="navigation:PhoneApplicationFrame">
<Border>
<toolkit:TransitioningContentControl
Content="{TemplateBinding Content}" Transition="DownTransition" />
</Border>
</ControlTemplate>
I am baffled why we need to roll our own smooth transitions for WinPhone7, but there it is. Jeff Brand (SlickThought.net) seems to have the best solution so far. Here is a nice article with a walkthrough video and sample code, though his sample code in the article was for the April CTP and appears to be broken in the Beta tools.
For a rather large project i have to figure out how (if possible) to resolve this problem. I have a full screen WPF application doing a slideshow - following an interval of e.g. 20 secs per slide. Now I have to investigate into the possibility of replacing the slideshow with a URL instead and have the user navigate the slides instead of changing slides every 10 seconds. The setup is like this:
First the timed slideshow will run, e.g. 5 slides
I show my web page and lets the user interact with the website (navigating)
When the user "Does something (this is the problem)" the website is removed from "slide" and the original slideshow is resumed
The container being shown is a WPF UserControl with an event that allows it to change to the next slide (call a Next() method). The IExporer is hosted within this control.
The problem im facing is this: how do i communicate from the website that my hosting application has to call the NExt() method?
The IExplorer showing the website is hosted within my WPF UserControl. Is there any way i can access some kind of event or anything else to help me determine if a particular page or a particular link has been pressed??
WebServices, files on disc, you name it, im ready to try anything :-)
Any advice or possible solution is appreciated.
If you use the WebBrowser control in your WPF application, you can call into C# classes using javascript from your html. For example, let's say you have a class similar to the following:
[ComVisible(true)]
public class JavaScriptBackEnd
{
public void onclick(string s)
{
MessageBox.Show(s);
}
}
Then initialize the WebBrowser control with the following code:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
webBrowser1.ObjectForScripting = new JavaScriptBackEnd();
webBrowser1.Navigate(new Uri(#"HTMLPage1.htm"));
}
From HTMLPage1.htm you can now call the JavaScriptBackEnd.onclick method with the following javascript:
function testclick() {
window.external.onclick('blabla');
}
When our app is started programatically (either through custom action in MSI installer or when starting a new instance) in Windows Vista (also happens in Windows 7 Beta) it won't appear in the taskbar and isn't focused. Alt-tabbing to it will make it appear in the taskbar properly and stay there.
What causes this? I've seen this in some other apps before as well, but not sure why. Out app is .NET WinForms app. Never see this happen in XP, only Vista and 7
Edit: Well, it seems like the only time this happens reproducibly is when it's run by the installer, I believe there's other times it occurs, but I might just be crazy. The launching code is a bit complex to post because we handle various command line launch parameters and it launches a signin form before actually launching the main app etc.
Has anyone had to deal with this scenario before and worked it out?
Try checking your main application form "Form Border" property.
If it's ToolWindow (Fixed or Sizable), try changing it to FixedDialog for example.
This solved the problem in my case.
The usual reason for this is that your main application window doesn't have the window styles that let Windows know it's a main application window (rather than a tool window or a dialog box). So Windows is having to guess based on how the app was started, etc.
Use Spy++ to complare the window styles (especially extended styles) if your window to that of some other window that doesn't have this problem. Are you missing the WS_EX_APPWINDOW style? Are any other styles/extended styles different from other top level windows?
G.So's answer made me find the solution for my problem, wich was caused by the fact that i had my form sizable from launch, but set to borderless in the load void.
If anyone is interested in how i managed to keep the switch to borderless and have it pop up as it should in the taskbar without any dirty hacks.. here it is..
Make a new event from the form on the form's "Shown" event, and put your line of code for switching to borderless in here. Problem solved :)
private void Form1_Shown(object sender, EventArgs e)
{
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
}
and for the lazy ones ;) >>>>
this.Shown += new EventHandler(Form1_Shown);
Thanks again G.So for clearing up what could cause this in the first place.
I stuggled with this issue as well, and found like a previous commenter said, you cannot have anything in the form's Load() event that changes that FormBorderStyle property. Move anything that changes it to the Shown() event.
Well, one solution is to use a hack like this. That's really not what it's for.
Usually the decision of whether a window will be in the taskbar or not is based on the border styles it uses. The article I linked to provides a bit more detail. The article's comment about the window having an owner or not is quite possible highly relevant to your issue, since the window might somehow be getting a different owner when launched by the installer.
That article is in VB but it's all based around API calls so the info it provides is pretty language independent.
Never see this happen in XP, only Vista and 7
Maybe it's a bug in Vista...?
What happens if you call SetForegroundWindow() (or equivalent in .Net)?
Edit
I did of course mean "BringWindowToTop()".
Or do both.
We had this same problem and fixed it by setting the form property showintaskbar property to true.
Weird that all windows os's dont run apps in the same way!
In our situation, this was tracked down to the form's text property being changed within the Load event.
After putting this inside a BeginInvoke, this odd behaviour no longer happened.
Hope this helps anyone else.
Example
private void Form_Load(object sender, EventArgs e)
{
...
...
...
// this needs to be inside a BeginInvoke otherwise it messes with the taskbar visibility
this.BeginInvoke(new Action(() =>
{
this.Text = "Something new";
}));
...
...
...
}
We encountered the same issue, also in Windows 8. Sometimes the form was receiving correctly the focus, but say just ~30% of the time.
We tried different solutions, but actually the one that worked was the following:
private void OnFormShown(object sender, EventArgs e)
{
// Tell Windows that the Form is a main application window
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
// Even if true, enforce the fact that we will the application on the taskbar
this.ShowInTaskbar = true;
// Put the window to the front and than back
this.BringToFront();
this.TopMost = true;
this.TopMost = false;
// 'Steal' the focus.
this.Activate();
}
Moreover, we ensure also not to set the title of the form during the Load event.