Error in web browser control navigating - c#

In my web browser app for wp7, i have two xaml pages. One is mainpage.xaml and other is web.xaml.
I have a youtube button in mainpage.xaml, if i click on it, it navigates to youtube.com in web.xaml. But if i press the device back button(to navigate to mainpage) after the youtube is fully navigated, then there is no error. But if i press the back button while the youtube is navigating then it throws an error. Error in recording the history i think(I also have history page to record the history). The error is - "Cannot write to a closed TextWriter". This error will also occur sometime for someother sites too. I have also added the image of that error. Can anyone help me with this? Thanks in advance for your help!
public partial class Web : PhoneApplicationPage
{
List<Uri> HistoryStack;
int HistoryStack_Index;
bool fromHistory;
bool navigationcancelled = false;
public IsolatedStorageFile historyFile = null;
public IsolatedStorageFileStream filestream = null;
public StreamWriter stream = null;
public Web()
{
InitializeComponent();
HistoryStack = new List<Uri>();
historyFile = IsolatedStorageFile.GetUserStoreForApplication();
if (historyFile.FileExists("History.txt"))
{
Error in this line--->filestream = historyFile.OpenFile("History.txt", System.IO.FileMode.Append, FileAccess.Write);--->Error in this line
stream = new StreamWriter(filestream);
}
else
{
filestream = historyFile.OpenFile("History.txt", System.IO.FileMode.Create);
stream = new StreamWriter(filestream);
}
HistoryStack_Index = 0;
fromHistory = false;
browsers[this.currentIndex].Navigated += new EventHandler<System.Windows.Navigation.NavigationEventArgs>(browsers_Navigated);
browsers[this.currentIndex].Navigating += new EventHandler<NavigatingEventArgs>(browsers_Navigating);
}
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
{
stream.Close();
}
}
private void browsers_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
if (!fromHistory)
{
if (HistoryStack_Index < HistoryStack.Count)
{
HistoryStack.RemoveRange(HistoryStack_Index, HistoryStack.Count - HistoryStack_Index);
}
HistoryStack.Add(e.Uri);
//HistoryURL temp = new HistoryURL();
//temp.URL = e.Uri.ToString();
//app.historyList.Add(temp);
Thread.Sleep(100);
Dispatcher.BeginInvoke(() =>
{
string title = (string)browsers[this.currentIndex].InvokeScript("eval", "document.title.toString()");
stream.WriteLine(title + ";" + e.Uri.ToString());---> **Error in this line.**
});
}
HistoryStack_Index += 1;
}
fromHistory = false;
navigationcancelled = false;
}

If I understand this correctly you are having 2 handlers for navigated event (OnNavigatedFrom and browsers_Navigated).
The problem probably is that in OnNavigatedFrom you are calling stream.Close(); so stream.WriteLine will fail the next time it is called since the stream was closed.
Try moving stream.Close(); to the application close event and use stream.Flush() after stream.WriteLine.

Related

How can I print a pdf document from Xamarin.Forms UWP?

I have a Xamarin.Forms application that supports only UWP. I cannot find a way to print a pdf document. Whatever I have seen on the web, for some reason doesn't work for me. E.g. I tried
https://www.syncfusion.com/kb/8767/how-to-print-pdf-documents-in-xamarin-forms-platform
It lets me print, but the preview in the print dialog never shows up, and the progress indicator just keeps rotating forever.
I also tried http://zawayasoft.com/2018/03/13/uwp-print-pdf-files-silently-without-print-dialog/
This gives me errors that I cannot fix.
So I wonder if somebody can suggest something else that would actually work. Maybe something newer than what I have tried (I use VS 2017). Printing without the printing dialog would be preferable.
Thank you in advance.
I used a very dirty hack to do that!
What I had to do was to try to print the image version of the pdf (I did the conversion in backend) and then used the following DependencyInjection:
Inside my Print class in UWP project:
class Print : IPrint
{
void IPrint.Print(byte[] content)
{
Print_UWP printing = new Print_UWP();
printing.PrintUWpAsync(content);
}
}
and the class responsible for printing in uwp:
public class Print_UWP
{
PrintManager printmgr = PrintManager.GetForCurrentView();
PrintDocument PrintDoc = null;
PrintDocument printDoc;
PrintTask Task = null;
Windows.UI.Xaml.Controls.Image ViewToPrint = new Windows.UI.Xaml.Controls.Image();
public Print_UWP()
{
printmgr.PrintTaskRequested += Printmgr_PrintTaskRequested;
}
public async void PrintUWpAsync(byte[] imageData)
{
int i = 0;
while (i < 5)
{
try
{
BitmapImage biSource = new BitmapImage();
using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
{
await stream.WriteAsync(imageData.AsBuffer());
stream.Seek(0);
await biSource.SetSourceAsync(stream);
}
ViewToPrint.Source = biSource;
if (PrintDoc != null)
{
printDoc.GetPreviewPage -= PrintDoc_GetPreviewPage;
printDoc.Paginate -= PrintDoc_Paginate;
printDoc.AddPages -= PrintDoc_AddPages;
}
this.printDoc = new PrintDocument();
try
{
printDoc.GetPreviewPage += PrintDoc_GetPreviewPage;
printDoc.Paginate += PrintDoc_Paginate;
printDoc.AddPages += PrintDoc_AddPages;
bool showprint = await PrintManager.ShowPrintUIAsync();
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
}
// printmgr = null;
// printDoc = null;
// Task = null;
PrintDoc = null;
GC.Collect();
printmgr.PrintTaskRequested -= Printmgr_PrintTaskRequested;
break;
}
catch (Exception e)
{
i++;
}
}
}
private void Printmgr_PrintTaskRequested(PrintManager sender, PrintTaskRequestedEventArgs args)
{
var deff = args.Request.GetDeferral();
Task = args.Request.CreatePrintTask("Invoice", OnPrintTaskSourceRequested);
deff.Complete();
}
async void OnPrintTaskSourceRequested(PrintTaskSourceRequestedArgs args)
{
var def = args.GetDeferral();
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
args.SetSource(printDoc.DocumentSource);
});
def.Complete();
}
private void PrintDoc_AddPages(object sender, AddPagesEventArgs e)
{
printDoc.AddPage(ViewToPrint);
printDoc.AddPagesComplete();
}
private void PrintDoc_Paginate(object sender, PaginateEventArgs e)
{
PrintTaskOptions opt = Task.Options;
printDoc.SetPreviewPageCount(1, PreviewPageCountType.Final);
}
private void PrintDoc_GetPreviewPage(object sender, GetPreviewPageEventArgs e)
{
printDoc.SetPreviewPage(e.PageNumber, ViewToPrint);
}
}
Please note that this is not a perfect solution and sometimes it crashes without actually being able to trace the exception (which is really strange) so I am sure there must be better answers even though it does the job.

Sending Image from WPF to Web API, thread error

So, I want to send the image from my WPF app to the Web API controller. When I get the image as BitmapImage and try to send it, I get the error "the calling thread cannot access this object because a different thread owns it". I don't see how am I modifying UI and why do I get the error. Here's the code:
WPF code:
private void BtnSendImage_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.InitialDirectory = Environment.SpecialFolder.MyDocuments.ToString();
BitmapImage slika = null;
if (ofd.ShowDialog() == true)
{
odabranaSlika = ofd.FileName;
Uri adresa = new Uri(odabranaSlika, UriKind.Absolute);
slika = new BitmapImage(adresa);
ItemDAL idal = new ItemDAL();
if (idal.SendImage(slika))
{
MessageBox.Show("Yay!");
}
else
{
MessageBox.Show("Awwww");
}
}
}
Method SendImage from the ItemDAL class (the code stops at postResult.Wait() part):
public bool SendImage(BitmapImage bmp)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:52407/");
var postResult = client.PostAsJsonAsync<BitmapImage>("api/values/postimage", bmp);
postResult.Wait();
var result = postResult.Result;
if (result.IsSuccessStatusCode)
{
return true;
}
else
{
return false;
}
}
}
What am I doing wrong? I know I'm not suppose to modify UI, unless it's from the main thread, bot how is this doing anything to the UI?

Implementing a camera directly in the application

I am implementing a camera function directly in an app, as I do not want to use Intent to open the default camera application. I have followed the code provided here:
The app crashes as soon as the photo gets taken, with the following error message:
Java.Lang.RuntimeException: Fail to connect to camera service
Here is how I set it up. I have ommited the unneccessary code.
namespace camera_test
{
[Activity(Label = "#string/app_name", Theme = "#style/AppTheme", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Android.Support.V7.App.AppCompatActivity, Android.Hardware.Camera.IPictureCallback, Android.Hardware.Camera.IPreviewCallback,
Android.Hardware.Camera.IShutterCallback, ISurfaceHolderCallback
{
static Android.Hardware.Camera camera = null;
Button btnStart;
Button btnEnd;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
SurfaceView surface = (SurfaceView)FindViewById(Resource.Id.surface);
var holder = surface.Holder;
holder.AddCallback(this);
holder.SetType(Android.Views.SurfaceType.PushBuffers);
btnStart = FindViewById<Button>(Resource.Id.buttonStart);
btnEnd = FindViewById<Button>(Resource.Id.buttonEnd);
btnStart.Click += BtnStart_Click;
btnEnd.Click += BtnEnd_Click;
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); StrictMode.SetVmPolicy(builder.Build());
}
private void BtnStart_Click(object sender, EventArgs e)
{
camera.StartPreview();
private void BtnEnd_Click(object sender, EventArgs e)
{
Android.Hardware.Camera.Parameters p = camera.GetParameters();
p.PictureFormat = Android.Graphics.ImageFormatType.Jpeg;
camera.SetParameters(p);
camera.TakePicture(this, this, this);
StartActivity(typeof(MainActivity));
}
void Android.Hardware.Camera.IPictureCallback.OnPictureTaken(byte[] data, Android.Hardware.Camera camera)
{
Java.IO.FileOutputStream outStream = null;
Java.IO.File dataDir = Android.OS.Environment.ExternalStorageDirectory;
DateTime DT = DateTime.Now;
String DateTimeStamp = DT.Year.ToString("D4") + "-" + DT.Month.ToString("D2") + "-" + DT.Day.ToString("D2") + "-" + DT.Hour.ToString("D2") + DT.Minute.ToString("D2") + DT.Second.ToString("D2");
String PictureFilename = "Photo-" + DateTimeStamp + ".jpg";
if (data != null)
{
try
{
outStream = new Java.IO.FileOutputStream(dataDir + "/" + PictureFilename);
outStream.Write(data);
outStream.Close();
}
catch (FileNotFoundException e)
{
System.Console.Out.WriteLine(e.Message);
}
catch (IOException ie)
{
System.Console.Out.WriteLine(ie.Message);
}
}
}
void Android.Hardware.Camera.IPreviewCallback.OnPreviewFrame(byte[] b, Android.Hardware.Camera c)
{
}
void Android.Hardware.Camera.IShutterCallback.OnShutter()
{
}
public void SurfaceCreated(ISurfaceHolder holder)
{
try
{
camera = Android.Hardware.Camera.Open();
Android.Hardware.Camera.Parameters p = camera.GetParameters();
p.PictureFormat = Android.Graphics.ImageFormatType.Jpeg;
camera.SetParameters(p);
camera.SetPreviewCallback(this);
camera.Lock();
camera.SetPreviewDisplay(holder);
// camera.StartPreview();
}
catch (IOException e)
{
}
}
public void SurfaceDestroyed(ISurfaceHolder holder)
{
camera.Unlock();
camera.StopPreview();
camera.SetPreviewCallback(null);
camera.Release();
camera = null;
}
public void SurfaceChanged(ISurfaceHolder holder, Android.Graphics.Format f, int i, int j)
{
}
}
}
I am guessing it has something to do with the way in which the camera is opened and closed, but I can't figure out how to solve this problem. Note that the start button correctly starts the camera viewer. It is only when the end button is clicked does the app crash. Any help or suggestions would be appreciated. Also, I know that camera has been depreciated. Thanks.
UPDATE:
The error occurs when:
the device changes orientation
or when I call this line: StartActivity(typeof(MainActivity));.
I.e, the error occurs when the acitvity gets restarted (I think that if the orientation changes then it restarts the activity as well). I have no idea how else to restart my activity because I need to. Interestingly, if I switch to a different activity then switch back to my main activity that has the camera function, the error does not occure. I am very puzzled.
Is there a reason why you use the deprecated camera api?
You should use camera2:
https://developer.android.com/reference/android/hardware/camera2/package-summary
Xamarin also provides a basic example for this:
https://developer.xamarin.com/samples/monodroid/android5.0/Camera2Basic/

Running a Webbrowser thread in a task

I have a program that runs and starts 2 long running tasks. One of the tasks is a web scraper in which I have to use the WebBrowser ActiveX control so that I can get the rendered page. In order to use the control I have to start a thread so that I can set the apartment state for the message loop. When I do this, the proogram works fine, or at least for the first page that is fetched. Subsequent pages/calls, the webbrowser times out and it's state seems to remain at "uninitialized". In tracing my code, I never see the "HandleDestroyed" fire for the WebClient.
What do I need to do to Properly Destroy the WebBrowser control and or my own class in order for it to be reused again.
public static string AXFetch(string url, string ua)
{
TestBrowser TB = new TestBrowser();
Thread th = new Thread(() => TB.MakeLiRequest(url,ua));
th.SetApartmentState(ApartmentState.STA);
th.Start();
th.Join(new TimeSpan(0, 0, 90)); //90 second timeout
SiteData = TB.DocumentText;
TB = null;
return SiteData;
}
class TestBrowser
{
public string DocumentText = "";
private bool DocCompleted = false;
public TestBrowser()
{
}
private void reset_fetch_status()
{
this.DocCompleted = false;
this.DocumentText = "";
}
public void MakeLiRequest(string url, string UA)
{
reset_fetch_status();
using (WebBrowser wb = new WebBrowser())
{
wb.Visible = false;
wb.AllowNavigation = true;
wb.ScriptErrorsSuppressed = true;
wb.DocumentCompleted += this.wb_DocumentCompleted;
wb.Navigate(url, "_self", null, "User-Agent: " + UA + "\r\n");
WaitForPage();
wb.Url = null;
wb.DocumentCompleted -= this.wb_DocumentCompleted;
}
}
private void HandleDestroyed(Object sender, EventArgs e)
{
//This never seems to fire, I don't knwo why
Logging.DoLog("You are in the Control.HandleDestroyed event.");
}
private bool WaitForPage()
{
int timer = 0;
while (this.DocCompleted == false)
{
Application.DoEvents();
System.Threading.Thread.Sleep(100);
++timer;
if (timer == (PageTimeOut * 10))
{
Console.WriteLine("WebBrowser Timeout has been reached");
Application.Exit();
return false;
}
}
return true;
}
private void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser wb = (WebBrowser)sender;
if (wb.ReadyState == WebBrowserReadyState.Complete)
{
this.DocumentText = wb.DocumentText;
this.DocCompleted = true;
}
}
}
On handle destroyed will only be called by the parent form.
If you were to try to access from the webbrowser control you would get this error:
Error 1 Cannot access protected member
'System.Windows.Forms.Control.OnHandleDestroyed(System.EventArgs)' via a
qualifier of type 'System.Windows.Forms.WebBrowser'; the qualifier must be of type 'stackoverflowpost47036339.Form1' (or derived from it)
Also you are not hooking it up. But since you haven't given your web browser any parent form, It can't be called. This is how you would hook it up to the parent form.
form1.HandleDestroyed += Form1_HandleDestroyed;
}
void Form1_HandleDestroyed(object sender, EventArgs e)
{
}

C# Add WMP dynamically to form (currently: audio playing, not showing video)

I'm trying to load the WindowsMediaPlayer control dynamically, but I can't get it to work properly.
The code as is, seems to play the audio (and probably video) but does not show the video on the form. The form keeps blank and the audio is playing. (playing a WVM file, cant be encoder issue) I'm importing the WMPLib.
WindowsMediaPlayer videoPlayer;
public void createContent(Form form) {
PlayFile("F:\\Videos\\CantTouchThis.wmv");
}
private void PlayFile(string url) {
videoPlayer = new WindowsMediaPlayer();
videoPlayer.PlayStateChange +=
new WMPLib._WMPOCXEvents_PlayStateChangeEventHandler(Player_PlayStateChange);
videoPlayer.MediaError +=
new WMPLib._WMPOCXEvents_MediaErrorEventHandler(Player_MediaError);
videoPlayer.URL = url;
videoPlayer.controls.play();
}
private void Player_PlayStateChange(int NewState) {
if ((WMPLib.WMPPlayState)NewState == WMPLib.WMPPlayState.wmppsStopped) {
}
}
private void Player_MediaError(object pMediaObject) {
MessageBox.Show("Cannot play media file.");
}
Help with getting this to work would be highly appreciated.
I've found the solution. Here it is for anyone who ever needs it in the future.
The code is:
private static AxWMPLib.AxWindowsMediaPlayer wmPlayer;
public static void AddMediaPlayer(Form form1) {
Button b1 = new Button();
b1.Text = "Button";
try {
wmPlayer = new AxWMPLib.AxWindowsMediaPlayer();
((System.ComponentModel.ISupportInitialize)(wmPlayer)).BeginInit();
wmPlayer.Name = "wmPlayer";
wmPlayer.Enabled = true;
wmPlayer.Dock = System.Windows.Forms.DockStyle.Fill;
form1.Controls.Add(wmPlayer);
((System.ComponentModel.ISupportInitialize)(wmPlayer)).EndInit();
// After initialization you can customize the Media Player
wmPlayer.uiMode = "none";
wmPlayer.URL = #"C:\ProjectSilver\assets\RadarDetectie\general\inlog_confirm.ogv";
wmPlayer.Ctlcontrols.play();
}
catch { }
Don't forget to import the library AxWMPLib.
After this you'll need to add [STAThread] on top of your class, otherwise you will get an exception.
Goodluck!

Categories