I have an app with a ListBox; when the user taps an item i launch a new page that invoke a MVVM method and the fills its ListBox. When the user taps the first ListBox it does not change page immediately, waits 2-3 seconds and then shows the new page and it is not responsive. How can i activate the new page, showing the ProgressIndicator and fill the new list?
Here is the code for the second list:
protected override async void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
int id;
if (NavigationContext.QueryString.ContainsKey("id"))
{
id = Convert.ToInt16(NavigationContext.QueryString["id"]);
SystemTray.SetIsVisible(this, true);
SystemTray.SetOpacity(this, 0.5);
progressIndicator = new ProgressIndicator();
progressIndicator.IsVisible = true;
progressIndicator.IsIndeterminate = true;
SystemTray.SetProgressIndicator(this, progressIndicator);
var x=await App.viewModel.MyDBMethod(id);
this.DataContext = App.viewModel;
this.mPivot.SelectedIndex = 0;
progressIndicator.IsVisible = false;
progressIndicator.IsIndeterminate = false;
}
}
}
Related
I am having an issue with my code to add button from json where the first attempt i click add button, the menuflyout won't have any respond but second click attempt then it will work properly.
Can advise did i do anything wrong? Thanks.
private async void AddButton_Click(object sender, RoutedEventArgs e)
{
List<ClientList> clientLists;
var jsonSerializer = new DataContractJsonSerializer(typeof(List<ClientList>));
var myStream = await ApplicationData.Current.LocalFolder.OpenStreamForReadAsync(CLIENTSLIST);
clientLists = (List<ClientList>)jsonSerializer.ReadObject(myStream);
var menuFlyout = new MenuFlyout();
int isEmpty = myGrid.Children.Count;
if (isEmpty == 0)
{
foreach (var device in clientLists)
{
var menuFlyoutItem = new MenuFlyoutItem() { Name = device.clientname, Text = device.clientname };
menuFlyoutItem.Tag = device.clientaddress;
menuFlyoutItem.Click += AddMenuFlyoutItem_Click;
menuFlyout.Items.Add(menuFlyoutItem);
}
}else
{
foreach (var device in clientLists)
{
bool toAddButton = true;
foreach (Button btn in myGrid.Children.OfType<Button>())
{
if (btn.Content.ToString() == device.clientname)
{
toAddButton = false;
}
}
if (toAddButton)
{
var menuFlyoutItem = new MenuFlyoutItem() { Name = device.clientname, Text = device.clientname };
menuFlyoutItem.Tag = device.clientaddress;
menuFlyoutItem.Click += AddMenuFlyoutItem_Click;
menuFlyout.Items.Add(menuFlyoutItem);
}
}
}
AddButton.Flyout = menuFlyout;
}
The problem is you are loading the data asynchronously here:
var myStream = await ApplicationData.Current.LocalFolder.OpenStreamForReadAsync(CLIENTSLIST);
When this happens, UI continues executing the Click event, so the button is clicked (and Flyout is null the first time) and Flyout will never display. You should rather load the Flyout before that - either when the page loads or when the data source changes, so that when the user clicks, the flyout is already there. Doing loading in Click is simply too late, if you need an asynchronous operation to finish.
Alternatively you could set the flyout right at the start:
private async void AddButton_Click(object sender, RoutedEventArgs e)
{
var menuFlyout = new MenuFlyout();
AddButton.Flyout = menuFlyout;
List<ClientList> clientLists;
var jsonSerializer = new DataContractJsonSerializer(typeof(List<ClientList>));
var myStream = await ApplicationData.Current.LocalFolder.OpenStreamForReadAsync(CLIENTSLIST);
clientLists = (List<ClientList>)jsonSerializer.ReadObject(myStream);
int isEmpty = myGrid.Children.Count;
if (isEmpty == 0)
{
foreach (var device in clientLists)
{
var menuFlyoutItem = new MenuFlyoutItem() { Name = device.clientname, Text = device.clientname };
menuFlyoutItem.Tag = device.clientaddress;
menuFlyoutItem.Click += AddMenuFlyoutItem_Click;
menuFlyout.Items.Add(menuFlyoutItem);
}
}else
{
foreach (var device in clientLists)
{
bool toAddButton = true;
foreach (Button btn in myGrid.Children.OfType<Button>())
{
if (btn.Content.ToString() == device.clientname)
{
toAddButton = false;
}
}
if (toAddButton)
{
var menuFlyoutItem = new MenuFlyoutItem() { Name = device.clientname, Text = device.clientname };
menuFlyoutItem.Tag = device.clientaddress;
menuFlyoutItem.Click += AddMenuFlyoutItem_Click;
menuFlyout.Items.Add(menuFlyoutItem);
}
}
}
}
This way, the flyout will appear, but will be empty until the asynchronous loading finishes and the items are actually added. Here you are just reading a file, so it should be barely noticeable. Although not as clean as pre-loading the flyout, it should get the job done too.
im quite new to c# and Xamarin and I've just encountered a problem. I can't seem to be able to set the back button title on a navigation page. Ive tried using the static SetBackButtonTitle method but it does not seem to set the back button to the title I want which is
'Test' but instead its giving me the 'default' title which is "Back".
// The root page of your application
var content = new ContentPage();
var CompanyName = new Label();
CompanyName.HorizontalTextAlignment = TextAlignment.Center;
CompanyName.Text = "Test";
var NextPage = new Button();
NextPage.Text = "Next Page";
NextPage.Font = Font.SystemFontOfSize(NamedSize.Large);
NextPage.BorderWidth = 1;
NextPage.HorizontalOptions = LayoutOptions.Center;
NextPage.VerticalOptions = LayoutOptions.CenterAndExpand;
var layout = new StackLayout();
layout.VerticalOptions = LayoutOptions.CenterAndExpand;
layout.Children.Add(CompanyName);
layout.Children.Add(NextPage);
content.Content = layout;
var content2 = new ContentPage();
var navigation = new NavigationPage(content);
NavigationPage.SetHasBackButton(navigation,true);
NavigationPage.SetBackButtonTitle(navigation,"Test");
NextPage.Clicked += NextPageClicked;
async void NextPageClicked(object sender, EventArgs e)
{
await navigation.PushAsync(content2);
}
MainPage = navigation;
}
If you want to change the back button's title(at the left in the navigation bar) in the second page, you should call the method SetBackButtonTitle with first page as parameter. So please modify NavigationPage.SetBackButtonTitle(navigation,"Test"); to NavigationPage.SetBackButtonTitle(content,"Test");
For those who use Xamarin.Forms WPF if you want to change back button title you can do this:
protected override void OnDisappearing()
{
base.OnDisappearing();
Title = "";
}
protected override void OnAppearing()
{
base.OnAppearing();
Title = "MyTitle";
}
Hi I have one gridview on the left and I have Multiview pane on the right. Basically what I am trying to do is when the use click select in the gridview, the information of that row will display in the Multiview.
I have two view.
View 1 contains label saying please select row to view full details.
View 2 basically retrieving all the necessary data.
The problem is, in my view 2, I do allow user to update the data. When the user updates the data and save, the view will go back to its initial view. And when the user click on the same row, it will then display the updated information.
How can I do such that when they save the changes, the view will show the updated information?
I have tried putting updatepanel but it does not work too.
CODE BEHIND:
protected void Page_Load(object sender, EventArgs e)
{
xxBLL schBLL = new xxBLL ();
GVFBAcc.DataSource = schBLL.getInfo();
GVFBAcc.DataBind();
MainView.ActiveViewIndex = 1;
}
protected void GVFBAcc_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
string Selectedid = GVFBAcc.SelectedRow.Cells[1].Text;//get user id
int selectedIdtoPass = Convert.ToInt32(Selectedid);
xxBLL getRecord = new xxBLL ();
addInfo InfoRetrieve = new addInfo ();
InfoRetrieve = getRecord.getDetail(selectedIdtoPass);
lbid.Text = Convert.ToString(InfoRetrieve .info_id1);
lbType.Text = InfoRetrieve .type;
lbName.Text = InfoRetrieve .name;
lbAbb.Text = InfoRetrieve .abb;
MainView.ActiveViewIndex = 0;
}
catch (Exception ex)
{
lbMessage.Visible = true;
lbMessage.Text = "Please select a Row.";
}
}
protected void editInfo_Click(object sender, ImageClickEventArgs e)
{
MainView.ActiveViewIndex = 0;
string cIcon = editInfo.ImageUrl;
if (cIcon.Equals("~/images/edit.png"))
{
editInfo.ImageUrl = "~/images/save.png";
lblEdit.Text = "";
tbName.Text = lbName.Text;
tbAbb.Text = lbAbb.Text;
tbtype.Text = lbType.Text;
lbName.Visible = false;
lbAbb.Visible = false;
lbType.Visible = true;
tbName.Visible = true;
tbAbb.Visible = true;
tbtype.Visible = false;
}
else if (cIcon.Equals("~/images/save.png"))
{
addInfo[] update = new addInfo[1];
int id = Convert.ToInt32(lbid.Text);
string name = tbName.Text;
string abb = tbAbb.Text;
addInfo updated = new addInfo(name, id, abb);
update[0] = updated;
xxBLL obj = new xxBLL ();
if (obj.updateDetail(update))
{
editInfo.ImageUrl = "~/images/edit.png";
lbName.Visible = true;
lbAbb.Visible = true;
lbType.Visible = true;
tbName.Visible = false;
tbAbb.Visible = false;
tbtype.Visible = false;
lblEdit.Text = "Saved";
lblEdit.ForeColor = Color.Green;
tbName.Text = lbName.Text;
tbAbb.Text = lbAbb.Text;
tbtype.Text = lbType.Text;
}
}
}
When the user updates the data and save, the view will go back to its initial view. And when the user click on the same row, it will then display the updated information. How can I do such that when they save the changes, the view will show the updated information?
or alternative How do i call the button click event at page load so that when the user clicks the save button, it will display the updated infomation
I'm designing an article editor for my company and I'd like to be able to show a live preview of the article in a separate WebBrowser window/control. The WebBrowser control needs to refresh the page every time the user changes anything in one of the fields for the article.
Previously, I had the WebBrowser control on the same form, but for space reasons, I had to break it out onto a separate form and access it using a button on the editor form. However, since I moved that control into a separate form, the WebBrowser gains focus on every refresh, meaning I can type one character and then I have to click back to the textbox I was typing in.
My question: Is there a way to refresh that preview page in the background without it stealing the focus so that I can update the preview to reflect what the user is typing without interrupting the user while typing?
Here are the methods for showing and refreshing the preview, respectively:
private void buttonShowPreview_Click(object sender, EventArgs e)
{
if (buttonShowPreview.Tag == null)
{
Form browserForm = new Form();
browserForm.FormClosing += new FormClosingEventHandler(delegate(Object form, FormClosingEventArgs args)
{
if (args.CloseReason == CloseReason.UserClosing)
{
args.Cancel = true;
browserForm.Hide();
previewShowing = false;
}
});
browserForm.Size = new System.Drawing.Size(1024, 768);
browserForm.DesktopLocation = new System.Drawing.Point(0, 0);
browserForm.Text = "Article Preview";
preview = new WebBrowser();
browserForm.Controls.Add(preview);
preview.Dock = DockStyle.Fill;
preview.Navigate("about:blank");
buttonShowPreview.Tag = browserForm;
}
Form previewForm = buttonShowPreview.Tag as Form;
previewForm.Show();
previewShowing = true;
RefreshPreview();
}
private void RefreshPreview(string jumpToAnchor)
{
if (preview != null)
{
preview.Document.OpenNew(true);
preview.Document.Write(structuredContent.GetStructuredContentHTML(content, jumpToAnchor, false));
preview.Refresh();
}
}
Based on the answer by Robberechts here, try disabling the parent Form, updating your WebBrowser, then re-enabling the parent Form again in the DocumentCompleted() event:
private void buttonShowPreview_Click(object sender, EventArgs e)
{
if (buttonShowPreview.Tag == null)
{
Form browserForm = new Form();
browserForm.FormClosing += new FormClosingEventHandler(delegate(Object form, FormClosingEventArgs args)
{
if (args.CloseReason == CloseReason.UserClosing)
{
args.Cancel = true;
browserForm.Hide();
}
});
preview = new WebBrowser();
preview.DocumentCompleted += preview_DocumentCompleted; // handle the DocumentCompleted() event
browserForm.Controls.Add(preview);
preview.Dock = DockStyle.Fill;
preview.Navigate("about:blank");
buttonShowPreview.Tag = browserForm;
}
Form previewForm = buttonShowPreview.Tag as Form;
previewForm.Size = new System.Drawing.Size(1024, 768);
previewForm.DesktopLocation = new System.Drawing.Point(0, 0);
previewForm.Text = "Article Preview";
RefreshPreview();
previewForm.Show();
}
private void RefreshPreview(string jumpToAnchor)
{
if (preview != null && preview.Parent != null)
{
preview.Parent.Enabled = false; // disable parent form
preview.Document.OpenNew(true);
preview.Document.Write(structuredContent.GetStructuredContentHTML(content, jumpToAnchor, false));
preview.Refresh();
}
}
private void preview_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser wb = sender as WebBrowser;
if (wb.Parent != null)
{
wb.Parent.Enabled = true; // re-enable parent form
}
}
Purpose
I want to use secondary tile in my application that can pin the page to the start menu, and when the user click it show the page correctly.
Problem
The page that the user trying to pin to the start up menu contains the information needed to receive from the previous page; therefore, if the page is pinned to the start up menu, and is navigated directly to it, it will not receive all neccessary information to show on the page.
To store the information sent from page to page, I use PhoneApplicationService.Current.State to store the data that need to send to the next page. That data is the selected item from listbox.
My Sample Code
Here is the code that is to select item from the listbox to store, and sent to the next page
Product List.xaml.cs
namespace App_Skin_Test_Final_.All_Files.Product_Files
{
public partial class Product_List : PhoneApplicationPage
{
string pro_list_id;
public Product_List()
{
InitializeComponent();
// ===================================== Add Search application bar =====================================
// Show application bar
ApplicationBar = new ApplicationBar();
ApplicationBar.Mode = ApplicationBarMode.Default;
ApplicationBar.Opacity = 1.0;
ApplicationBar.IsVisible = true;
ApplicationBar.IsMenuEnabled = true;
// Search Application bar
ApplicationBarIconButton btnSearch = new ApplicationBarIconButton();
btnSearch.IconUri = new Uri("/images/Icon Application Bars/Search.png", UriKind.Relative);
btnSearch.Text = "Search";
ApplicationBar.Buttons.Add(btnSearch);
btnSearch.Click += btnSearch_Click;
}
// function Search application bar
private void btnSearch_Click(object sender, EventArgs e)
{
NavigationService.Navigate(new Uri("/All Files/Product Files/Search.xaml", UriKind.Relative));
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (NavigationContext.QueryString.TryGetValue("pro_list_id", out pro_list_id))
{
}
}
private void lst_product_Loaded(object sender, RoutedEventArgs e)
{
//MessageBox.Show(pro_cate_id);
XDocument data = XDocument.Load("All Files/Database XML/ProductsDry.xml");
var productListData = from q in data.Descendants("DryCategory")
from itemDry in q.Elements("ItemDry") // mean: itemDry in in DryCategory
where q.Attribute("DryCategoryId").Value == pro_list_id
select new ProductsDry
{
ItemDryName = itemDry.Attribute("ItemDryName").Value,
ItemDryImage = getImage(itemDry.Attribute("ItemDryImage").Value),
ItemDryId = itemDry.Attribute("ItemDryId").Value,
ItemDryIngredients = itemDry.Attribute("ItemDryIngredients").Value,
ItemDryDesc1 = itemDry.Attribute("ItemDryDesc1").Value,
ItemDryDesc2 = itemDry.Attribute("ItemDryDesc2").Value,
ItemDryUse = itemDry.Attribute("ItemDryUse").Value
// ItemDryLink=itemDry.Attribute("ItemDryLink").Value
};
lst_product.ItemsSource = productListData;
// NavigationService.GoBack();
}
private System.Windows.Media.ImageSource getImage(string p)
{
return new BitmapImage(new Uri(p, UriKind.Relative));
}
private void lst_product_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (lst_product.SelectedItem != null)
{
PhoneApplicationService.Current.State["myimage"] = (lst_product.SelectedItem as ProductsDry).ItemDryImage;
PhoneApplicationService.Current.State["ItemDryIngridient"] = (lst_product.SelectedItem as ProductsDry).ItemDryIngredients;
PhoneApplicationService.Current.State["ItemDryUse"] = (lst_product.SelectedItem as ProductsDry).ItemDryUse;
PhoneApplicationService.Current.State["ItemDryDesc1"] = (lst_product.SelectedItem as ProductsDry).ItemDryDesc1;
PhoneApplicationService.Current.State["ItemDryDesc2"] = (lst_product.SelectedItem as ProductsDry).ItemDryDesc2;
PhoneApplicationService.Current.State["ItemDryUse"] = (lst_product.SelectedItem as ProductsDry).ItemDryUse;
NavigationService.Navigate(new Uri("/All Files/Product Files/Dry/Product Detail.xaml?&pro_name=" + (lst_product.SelectedItem as ProductsDry).ItemDryName + "&pro_image=" + (lst_product.SelectedItem as ProductsDry).ItemDryImage, UriKind.Relative));
}
else return;
}
private void btnGoBack_Click(object sender, RoutedEventArgs e)
{
if (this.NavigationService.CanGoBack)
{
this.NavigationService.GoBack();
}
}
}
}
And here is the page to receive selected item information from the previouse page "Product List.xaml" and it is the page that I want user to pin specific product that they have selected.
Product Detail.xaml.cs
namespace App_Skin_Test_Final_.All_Files.Product_Files
{
public partial class Product_Detail : PhoneApplicationPage
{
string pro_name;
string pro_image;
string pro_ingridient;
//string pro_link;
string pro_use;
string pro_dryDesc1;
string pro_dryDesc2;
// ImageSource image;
private readonly string SecondaryTileUriSource = "Source=SecondaryTile";
public Product_Detail()
{
InitializeComponent();
// ===================================== Add Search application bar =====================================
// Show application bar
ApplicationBar = new ApplicationBar();
ApplicationBar.Mode = ApplicationBarMode.Default;
ApplicationBar.Opacity = 1.0;
ApplicationBar.IsVisible = true;
ApplicationBar.IsMenuEnabled = true;
// Search Application bar
ApplicationBarIconButton btnSearch = new ApplicationBarIconButton();
btnSearch.IconUri = new Uri("/images/Icon Application Bars/Search.png", UriKind.Relative);
btnSearch.Text = "Search";
ApplicationBar.Buttons.Add(btnSearch);
btnSearch.Click += btnSearch_Click;
ApplicationBarIconButton btnPin = new ApplicationBarIconButton();
btnPin.IconUri = new Uri("/images/Icon Application Bars/pin.png", UriKind.Relative);
btnPin.Text = "Pin";
ApplicationBar.Buttons.Add(btnPin);
btnPin.Click += btnPin_Click;
}
void btnPin_Click(object sender, EventArgs e)
{
// secondary tile can be created only as the result
// of user input in an application
ShellTile tile = this.FindTile(SecondaryTileUriSource);
if(tile==null)
{
//because the UI will navigate to Start
//When a new secondary tile is created
//only one secondary tile can be created at a time
StandardTileData tileData = this.GetSecondaryTileData();
MessageBox.Show("The SecondaryTileUriSource is " + SecondaryTileUriSource);
//having a unique NavigationUri is necessary for distinguishing this tile
string tileUri = string.Concat("/All Files/Product Files/Dry/Product Detail.xmal?", SecondaryTileUriSource);
// MessageBox.Show("the uri is " + tileUri);
ShellTile.Create(new Uri(tileUri, UriKind.Relative), tileData);
// ShellTile.Create(new Uri("/All Files/Product Files/Dry/Product Detail.xaml", UriKind.Relative), tileData);
}
}
// function Search application bar
private void btnSearch_Click(object sender, EventArgs e)
{
NavigationService.Navigate(new Uri("/All Files/Product Files/Search.xaml", UriKind.Relative));
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
// Check if the Secondar tile exists
ShellTile secondaryTile = this.FindTile(SecondaryTileUriSource);
if (secondaryTile != null)
{
// ***************************************************** tile.Delete();
MessageBox.Show("Secondary tile exist.");
}
if (NavigationContext.QueryString.TryGetValue("pro_name", out pro_name))
{
}
if (NavigationContext.QueryString.TryGetValue("pro_image", out pro_image))
{
}
txtbPro_Name.Text = pro_name;
BitmapImage bm = PhoneApplicationService.Current.State["myimage"] as BitmapImage;
img_Product.Source = bm;
// Ingridient Text
pro_ingridient = PhoneApplicationService.Current.State["ItemDryIngridient"] as string;
txtb_ingridient.Text = pro_ingridient;
// Find on Somaly store
//pro_link = PhoneApplicationService.Current.State["ItemDryLink"] as String;
//txtb_link = pro_link;
// How to use product
pro_use = PhoneApplicationService.Current.State["ItemDryUse"] as string;
txtb_howToUse.Text = pro_use;
// Description 1 and Description 2
pro_dryDesc1 = PhoneApplicationService.Current.State["ItemDryDesc1"] as string;
txtb_description1.Text = pro_dryDesc1;
pro_dryDesc2 = PhoneApplicationService.Current.State["ItemDryDesc2"] as string;
txtb_description2.Text = pro_dryDesc2;
// txtb_ingridient.Text = pro_image;
// image = getImage(pro_image);
// MessageBox.Show(image);
// img_Product.Source = image;
}
private ImageSource getImage(string img)
{
return new BitmapImage(new Uri(img, UriKind.Relative));
}
/*********************************************
* Create a Secondary Tile for pin application
*********************************************/
private StandardTileData GetSecondaryTileData()
{
StandardTileData titleData = new StandardTileData
{
Title = "Secondary Tile",
BackBackgroundImage = new Uri("/Images/Allures/Base/aba001.jpg", UriKind.Relative),
Count = 5,
BackTitle = "Secondary Tile",
BackgroundImage = new Uri("", UriKind.Relative),
BackContent = "WPG Add Remove Tile Sample"
};
return titleData;
}
private ShellTile FindTile(string partOfUri)
{
ShellTile shellTile = ShellTile.ActiveTiles.FirstOrDefault(
title => title.NavigationUri.ToString().Contains(partOfUri));
return shellTile;
}
}
}
When the user presses on pin application bar button on the Product Detail.xaml page, the page is pinned to the start up menu as normal; however, when they press on pinned page at the start up menu, it never navigate back to the Product Detail page. But if I comment out every line of PhoneApplicationService.Current.State in product detail.xaml.cs, it could navigate to the page but it does not show anything on the page, the information on the selected item.
How can I correct this error to show the page that the user pin to the start as normal?
Kindly help. Thanks
The direct issue is that when launching the app from the secondary tile, the values in the PhoneApplicationService.Current.State dictionary are not populated, so you cannot read them.
But even if you get around that and find out why the state is not populated, I see a bigger problem in the code. I imagine that you show a list of products, and can navigate to the details of each product, and want to allow the user to pin a specific product to the Start page. So, imagine that you store the selected product in the phone state dictionary and then pin the details. The you open the application and select another product - so it will be now stored in the app state, and tapping the pinned tile will open the second product details ...
My suggestion is to redesign the interaction between the pages - if you have some unique id that can identify the products, pass that id to the product detail page, and also store that same id in the uri of the secondary tile, like this:
new Uri("/All Files/Product Files/Dry/Product Detail.xaml?&item_id=" + itemId)
Then, in the OnNavigated() method of the product details page, read the id from the query string, then access the full list of products, locate the product with that id, and display it.
This way all navigations - from secondary tile, resuming the application, etc. will work correctly.