I'm trying to create a download manager for UWP in C#. I need to add ProgressBar for download progress, TextBlock for showing download status and another TextBox for displaying download file name. My code works fine when I compile only download manager's code separately (on a new uwp app). It shows progress properly in runtime.
My codes are-
private async void Downloadbtn_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
Uri url = new Uri(urlBox.Text);
string fileName = ResolveName(urlBox.Text);
FolderPicker folderPicker = new FolderPicker();
folderPicker.ViewMode = PickerViewMode.List;
folderPicker.FileTypeFilter.Add("*.*");
StorageFolder downloadfolder = await folderPicker.PickSingleFolderAsync();
if (folderPicker != null)
{
StorageFile downloadFile = await downloadfolder.CreateFileAsync(fileName, CreationCollisionOption.GenerateUniqueName);
BackgroundDownloader downloader = new BackgroundDownloader();
operation = downloader.CreateDownload(url, downloadFile);
try
{
TextBlock fileNameText = new TextBlock();
fileNameText.Text = fileName;
ProgressBar ProgressIndicator = new ProgressBar();
ProgressIndicator.Name = "progress";
TextBlock progressText = new TextBlock();
progressText.Name = "progressText";
StackPanel panel = new StackPanel();
panel.Children.Add(fileNameText);
panel.Children.Add(ProgressIndicator);
panel.Children.Add(progressText);
MainStack.Children.Add(panel);
cts = new CancellationTokenSource();
Progress<DownloadOperation> progressCallBack = new Progress<DownloadOperation>(Progress);
await operation.StartAsync().AsTask(cts.Token,progressCallBack);
}
catch (Exception)
{
await operation.ResultFile.DeleteAsync();
operation = null;
}
}
}
private string ResolveName(string fileName)
{
if (fileName.Contains("/"))
{
int last = fileName.LastIndexOf("/");
fileName = fileName.Substring(last + 1, fileName.Length - last - 1);
}
if (fileName.Contains("%20"))
{
fileName = fileName.Replace("%20", " ");
}
return fileName;
}
private void Progress(DownloadOperation operation)
{
ProgressBar c = new ProgressBar();
c = (ProgressBar)(MainStack.FindName("progress" ));
TextBlock c1 = new TextBlock();
c1 = (TextBlock)(MainStack.FindName("progressText"));
double received = operation.Progress.BytesReceived;
double toReceive = operation.Progress.TotalBytesToReceive;
double progress = received * 100 / toReceive;
((ProgressBar)c).Value = progress;
c1.Text = received + "KB received of " + toReceive + "KB";
if (received == toReceive)
c1.Text = "Download Completed";
}
MainStack is the stackpanel where new download and its ui elements are added.
But UI elements (progressbar, textblock) are not visible when I'm putting above codes in a different app like-
private async void GetDownloadData(Uri uri)
{
string fileName = ResolveName(uri.tostring());
FolderPicker folderPicker = new FolderPicker();
folderPicker.ViewMode = PickerViewMode.List;
folderPicker.FileTypeFilter.Add("*.*");
StorageFolder downloadfolder = await folderPicker.PickSingleFolderAsync();
if (folderPicker != null)
{
StorageFile downloadFile = await downloadfolder.CreateFileAsync(fileName, CreationCollisionOption.GenerateUniqueName);
BackgroundDownloader downloader = new BackgroundDownloader();
operation = downloader.CreateDownload(url, downloadFile);
try
{
TextBlock fileNameText = new TextBlock();
fileNameText.Text = fileName;
ProgressBar ProgressIndicator = new ProgressBar();
ProgressIndicator.Name = "progress" ;
TextBlock progressText = new TextBlock();
progressText.Name = "progressText";
StackPanel panel = new StackPanel();
panel.Children.Add(fileNameText);
panel.Children.Add(ProgressIndicator);
panel.Children.Add(progressText);
MainStack.Children.Add(panel);
cts = new CancellationTokenSource();
Progress<DownloadOperation> progressCallBack = new Progress<DownloadOperation>(Progress);
await operation.StartAsync().AsTask(cts.Token,progressCallBack);
}
catch (Exception)
{
await operation.ResultFile.DeleteAsync();
operation = null;
}
}
}
In the second code, I'm calling GetDownloadData(uri) method to initiate download rather than calling it upon button click event. And also this method is placed in different XAML page (other than main page).
The only problem with the second code is that, no progressbar or textblock is added at run time in MainStack (stackpanel). I tried solving this problem by replacing stackpanel with listview and listbox but problem doesn't resolve.
Any idea, what am I missing here.
Related
I'm trying to change an image on runtime but it's not working.
I have a user control that when you click on imagebtn it's opening a new window with a list of images.
the next step is to take the image selected from the list, close the new window, and put the image on the imagebtn.
the user control still opens in the background.
this is my code.
NewWindow:
private string myData;
public ImagesWindow()
{
InitializeComponent();
InitialImageList();
}
private async void InitialImageList()
{
//add try catch
string get = await HttpRequests.GetRequest(URLImages);
allJsonCategory = JsonConvert.DeserializeObject<List<ImageArray>>(get);
Console.WriteLine(get);
ImageBoxList.ItemsSource = images;
foreach (var item in allJsonCategory)
{
images.Add(item);
}
}
private void ImageBoxList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
selectedImage = (ImageArray)ImageBoxList.SelectedItem;
myData = selectedImage.full_path;
Console.WriteLine("you clicked on: " + selectedImage.name);
ProductsCategory pro = new ProductsCategory();
pro.imagePath = myData;
this.Close();
}
my usercontrol(in mainWindow):
public void setImage(string imagePath)
{
if (!imageURL.Equals(""))
{
Image imageBtn = new Image();
var imgUrl = new Uri(imagePath);
var imageData = new WebClient().DownloadData(imgUrl);
// or you can download it Async won't block your UI
// var imageData = await new WebClient().DownloadDataTaskAsync(imgUrl);
var bitmapImage = new BitmapImage { CacheOption = BitmapCacheOption.OnLoad };
bitmapImage.BeginInit();
bitmapImage.StreamSource = new MemoryStream(imageData);
bitmapImage.EndInit();
imageBtn.Source = bitmapImage;
//this.imageBtn.InvalidateVisual();
}
}
XAML of the image:
where is my mistake?
thank you all :)
Can anybody help me with this code in my Xamarin project. I am trying to set a loading wheel (to signify that an action is happening and to let the user know to wait) when the "Login" button is clicked. For some reason since the function is asynchronous the loading wheel is never set to visible when the API code is run. It just fails to show up when I click login, however, it still does the login function.
// Defined up above in the file
var loginButton = new Button
{
Text = "Login",
};
loginButton.BackgroundColor = Color.Navy;
loginButton.TextColor = Color.White;
loginButton.Clicked += OnLoginButtonClicked;
async void OnLoginButtonClicked(object sender, EventArgs e)
{
loadingWheel.IsVisible = true;
try
{
var restUrl = "*******";
var content = string.Empty;
using (var client = new HttpClient())
{
string body = "{\"UserName\":\"" + usernameEntry.Text + "\", \"Password\":\"" + passwordEntry.Text + "\"}";
var contentType = new StringContent(body, Encoding.UTF8, "application/json");
var result = client.PostAsync(restUrl, contentType).Result;
content = await result.Content.ReadAsStringAsync();
}
if (content.ToLower() != "false")
{
var menuPage = new MenuPage();
NavigationPage = new NavigationPage(new HomePage());
RootPage = new Views.MainPage();
RootPage.Master = menuPage;
RootPage.Detail = NavigationPage;
MainPage = RootPage;
}
else
{
messageLabel.Text = "Username or password incorrect. Please try again.";
passwordEntry.Text = string.Empty;
}
}
catch (Exception ex)
{
messageLabel.Text = "Please check the internet connection for the connectivity.";
}
}
If I comment out the entire try block then the loading wheel does show up. It just does not work with the code in there.
Can anybody help me solve this problem? Thanks.
I think you can try with BeginInvokeOnMainThread
Device.BeginInvokeOnMainThread (() => {
loadingWheel.IsVisible = true;
});
UPDATE
I have also create this REPO... it works without BeginInvodeOnMainThread
public class MyPage6 : ContentPage
{
ActivityIndicator _ac = new ActivityIndicator { IsVisible = false, IsRunning = false };
public MyPage6()
{
Button b = new Button {Text = "Press for ActivityIndicator" };
b.Clicked += B_Clicked;
Content = new StackLayout
{
Children = {
_ac,
b,
new Label { Text = "Hello ContentPage" }
}
};
}
async void B_Clicked(object sender, EventArgs e)
{
_ac.IsRunning = true;
_ac.IsVisible = true;
await Task.Delay(2000);
_ac.IsRunning = false;
_ac.IsVisible = false;
}
}
First i'm getting list of all my youtube videos and add the list to a listBox:
static List<string> videosList = new List<string>();
static List<string> videosUrl = new List<string>();
public async void RetrieveUploadsList()
{
UserCredentials();
var youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = Assembly.GetExecutingAssembly().GetName().Name
});
var channelsListRequest = youtubeService.Channels.List("contentDetails");
channelsListRequest.Mine = true;
var channelsListResponse = await channelsListRequest.ExecuteAsync();
foreach (var channel in channelsListResponse.Items)
{
var uploadsListId = channel.ContentDetails.RelatedPlaylists.Uploads;
Console.WriteLine("Videos in list {0}", uploadsListId);
var nextPageToken = "";
while (nextPageToken != null)
{
var playlistItemsListRequest = youtubeService.PlaylistItems.List("snippet");
playlistItemsListRequest.PlaylistId = uploadsListId;
playlistItemsListRequest.MaxResults = 50;
playlistItemsListRequest.PageToken = nextPageToken;
var playlistItemsListResponse = await playlistItemsListRequest.ExecuteAsync();
foreach (var playlistItem in playlistItemsListResponse.Items)
{
videosList.Add(playlistItem.Snippet.Title + " " + playlistItem.Snippet.ResourceId.VideoId);
videosUrl.Add("http://www.youtube.com/v/" + playlistItem.Snippet.ResourceId.VideoId);
listBox1.Items.Add(playlistItem.Snippet.Title + " " + playlistItem.Snippet.PublishedAt);
}
nextPageToken = playlistItemsListResponse.NextPageToken;
}
}
if (this.listBox1.Items.Count > 80)
{
this.listBox1.SelectedIndex = 80;
axWindowsMediaPlayer1.URL = videosUrl[80];
}
}
Then listBox1 selected index changed event:
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
axWindowsMediaPlayer1.URL = videosUrl[listBox1.SelectedIndex];
}
And last the windows media player control playstate change event:
private void axWindowsMediaPlayer1_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
e.newState = 2;
if (e.newState == 3)
{
axWindowsMediaPlayer1.fullScreen = true;
}
}
The problem is that before i'm clicking anything to start playing any video from the list it's getting to the PlayStateChange event and trying to do the fullScreen = true seems like it's trying to start playing the video automatic.
So i added this:
e.newState = 2;
The code 2 mean pause. But now even if i will click the play button it will make this line e.newState = 2; and it will be paused.
I can't find a way to make it not to start playing it automatic or thinking it does.
You can see in this link all the codes for e.newState
newState codes
Code 1 = stopped
Code 2 = paused
Code 3 = playing
My app downloads several images from the internet and shows progress of the overall download in one single progress bar. The problems is that the progress isn't being updated correctly when using a BackgroundTransferService.
This is what I have.
From my PhoneApplicationPage_Loaded I call download a list of the images urls that i want to download.
WebClient wc = new WebClient();
wc.DownloadStringCompleted += wc_DownloadStringCompleted;
wc.DownloadStringAsync(new Uri(MyDownloadList), null);
Then in the wc_DownloadStringCompleted I register a custom event DownloadProgress in my DownloadManagerClass which updated the progress bar in the UI pbDownloadProgress
Then I call the code which adds a new BackgroundTransferRequest and register the TransferStatusChanged and TransferProgressChanged (that resides in the DownloadManagerClass).
void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
var up = e.Result;
Dispatcher.BeginInvoke(() => txtDownloadProgressText.Text = "Downloading");
downloadManager.DownloadProgress += (src, args) =>
{
Debug.WriteLine("Updating progress to " + args.Progress ` 100);
Dispatcher.BeginInvoke(() =>
{
if (pbDownloadProgress.IsIndeterminate)
{
pbDownloadProgress.IsIndeterminate = false;
pbDownloadProgress.Minimum = 0;
pbDownloadProgress.Maximum = 100;
}
pbDownloadProgress.Value = args.Progress * 100;
});
};
BackgroundWorker bg = new BackgroundWorker();
bg.DoWork += (s, ev) =>
{
downloadManager.DownloadImages(up);
};
bg.RunWorkerAsync();
}
}
And my DownloadImages method
internal void DownloadImages(String result)
{
List<String> URLs = ConvertStringToListUrls(result);
var localFile = IsolatedStorageFile.GetUserStoreForApplication();
if (!localFile.DirectoryExists(TRANSFERS_DIRECTORY))
{
localFile.CreateDirectory(TRANSFERS_DIRECTORY);
}
numberDownloadedItems = 0;
totalDownloadingItems = URLs.Count;
foreach (String item in URLs)
{
Debug.WriteLine("Adding Uri:" + uri);
Uri transferUri = new Uri(Uri.EscapeUriString(item), UriKind.RelativeOrAbsolute);
BackgroundTransferRequest transferRequest = new BackgroundTransferRequest(transferUri);
transferRequest.Method = "GET";
string downloadFile = transferFileName.Substring(transferFileName.LastIndexOf("/") + 1);
Uri downloadUri = new Uri(TRANSFERS_DIRECTORY + "/" + downloadFile, UriKind.RelativeOrAbsolute);
transferRequest.DownloadLocation = downloadUri;
transferRequest.TransferStatusChanged += new EventHandler<BackgroundTransferEventArgs>(transfer_TransferStatusChanged);
transferRequest.Tag = downloadFile;
transferRequest.TransferPreferences = TransferPreferences.AllowCellularAndBattery;
BackgroundTransferService.Add(transferRequest);
Debug.WriteLine("Adding transferID: " + transferRequest.RequestId);
}
}
Finally my transfer_TransferStatusChanged method which mainly calls the DownloadProgress event when one file is completed.
void transfer_TransferProgressChanged(object sender, BackgroundTransferEventArgs e)
{
if (transfer.TransferStatus == TransferStatus.Completed && (transfer.StatusCode == 200 || transfer.StatusCode == 206)) {
if (RemoveTransferRequest(transfer.RequestId))
if (DownloadProgress != null) DownloadProgress(this, new ProgressEventArgs(++numberDownloadedItems, totalDownloadingItems));
}
}
Every step seems to be working fine but the problem is that on the output I get the debug messages indicating the progress that should be updated (like the ones below) but the progressbar itself remains unchanged.
Removing transferID: {05ea9c10-025f-4e90-bc55-e9d36424b5f0}
10:37:27 AM:200: Updating progress to 14.2857142857143
Removing transferID: {e92f79fe-dc99-48b3-b0b1-76d3f5cedd51}
10:37:27 AM:651: Updating progress to 21.4285714285714
Removing transferID: {f61c8c9e-aa41-4e2a-8906-fca06961e69e}
10:37:28 AM:30: Updating progress to 28.5714285714286
Removing transferID: {46abc1df-37e6-432a-9b55-0adb3a8a2235}
I already tried to remove the dispatcher use, to reorganize the code but I can't seem to get it to work.
PS: I removed some exception catching from the code to keep it simpler
I want to show something like toast after some functionality performed. i-e I have a save button and I want that when it pressed then a toast should be shown with the text Record Saved etc. I read posts that show toasts are only for back-ground agents. I know someone will give me good guidance. please specify some code.
Thanks
You can use the Toast Prompt from the Coding4Fun Toolkit to perform a toast notification via code. After referencing the toolkit (ideally via NuGet) you can use it like this:
ToastPrompt toast = new ToastPrompt();
toast.Title = "Your app title";
toast.Message = "Record saved.";
toast.TextOrientation = Orientation.Horizontal;
toast.MillisecondsUntilHidden = 2000;
toast.ImageSource = new BitmapImage(new Uri("ApplicationIcon.png", UriKind.RelativeOrAbsolute));
toast.Show();
I prefer ProgressIndicator in my apps but you can use Popup or ToastPrompt.
Sample project.
// popup member
private Popup popup;
// creates popup
private Popup CreatePopup()
{
// text
TextBlock tb = new TextBlock();
tb.Foreground = (Brush)this.Resources["PhoneForegroundBrush"];
tb.FontSize = (double)this.Resources["PhoneFontSizeMedium"];
tb.Margin = new Thickness(24, 32, 24, 12);
tb.Text = "Custom toast message";
// grid wrapper
Grid grid = new Grid();
grid.Background = (Brush)this.Resources["PhoneAccentBrush"];
grid.Children.Add(tb);
grid.Width = this.ActualWidth;
// popup
Popup popup = new Popup();
popup.Child = grid;
return popup;
}
// hides popup
private void HidePopup()
{
SystemTray.BackgroundColor = (Color)this.Resources["PhoneBackgroundColor"];
this.popup.IsOpen = false;
}
// shows popup
private void ShowPopup()
{
SystemTray.BackgroundColor = (Color)this.Resources["PhoneAccentColor"];
if (this.popup == null)
{
this.popup = this.CreatePopup();
}
this.popup.IsOpen = true;
}
// shows and hides popup with a delay
private async void ButtonClick(object sender, RoutedEventArgs e)
{
this.ShowPopup();
await Task.Delay(2000);
this.HidePopup();
}
using Windows.UI.Notifications;
var toastXmlContent = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
var txtNodes = toastXmlContent.GetElementsByTagName("text");
txtNodes[0].AppendChild(toastXmlContent.CreateTextNode("First Line"));
txtNodes[1].AppendChild(toastXmlContent.CreateTextNode("Second Line" ));
var toast = new ToastNotification(toastXmlContent);
var toastNotifier = ToastNotificationManager.CreateToastNotifier();
toastNotifier.Show(toast);