I have a MasterDetailPage implemented:
public MasterPage()
{menuList = new List<Models.MasterPageItem>();
var index= new Models.MasterPageItem() { Title = "index", Icon =index.png, TargetType = typeof(Index.Index) };
var client= new Models.MasterPageItem() { Title = "Clients", Icon =client.png, TargetType = typeof(Login.Client) };
menuList.Add(index);
menuList.Add(client);
navigationDrawerList.ItemsSource = menuList;
Detail = new NavigationPage((Page)Activator.CreateInstance(typeof(Dashboard)));
}
private void OnMenuItemSelected(object sender, SelectedItemChangedEventArgs e){
Type page = item.TargetType;
Detail.Navigation.PushAsync((Page)Activator.CreateInstance(page));
IsPresented = false;
}
the problem is , if i click on client, the navigation works, but if i press back it works also , the problem when i click again on client , dosent work , i must navigate on index or another item , and the click on client , i can't navigate twice on same item.
as the name implies, SelectedItemChanged only fires on changes. So if you tap the same option twice in a row, it only fires once. The workaround is to set
navigationDrawerList.SelectedtedItem = null;
in the event handler before you havigate
Related
I have a page that is registered in the AppShell like this:
public AppShell()
{
InitializeComponent();
Routing.RegisterRoute(nameof(LesezeichenPage), typeof(LesezeichenPage));
}
...and the Flyout:
<FlyoutItem FlyoutDisplayOptions="AsMultipleItems" >
<ShellContent Title="Lesezeichen" Route="LesezeichenPage" ContentTemplate="{DataTemplate v:LesezeichenPage}">
</ShellContent>
</FlyoutItem>
Additionally the page can be opened from other pages in the App with an ImageButton:
Shell.Current.GoToAsync("LesezeichenPage");
The problem is with the following approach: I save an Observablecollection to my App's Properties on this page with the following method:
private void LesezeichenSpeichern(ContentPage contentPage)
{
var parentPage = (TabbedPage)contentPage.Parent;
parentPage.CurrentPage = parentPage.Children[1];
Bookmarks.Add(new Bookmark { Novene = PickedNovene, Tag = PickedTag, Date = DateTime.Today.ToString("d/M/yy"), ID = Bookmarks.Count }) ;
string LesezeichenJson = JsonConvert.SerializeObject(Bookmarks);
SetProperties("JsonLesezeichen", LesezeichenJson);
}
public async static void SetProperties(string property, object value)
{
var app = (App)Application.Current;
app.Properties[property] = value;
await app.SavePropertiesAsync();
}
When I open the page the Json will then be deserialised and added to an ObservableCollection in the constructor:
public LesezeichenViewModel()
{
Bookmarks = new ObservableCollection<Bookmark>();
////Lade Properties wenn in einer vorherigen Session gespeichert
if (Application.Current.Properties.ContainsKey("JsonLesezeichen"))
{
string savedLesezeichen = Application.Current.Properties["JsonLesezeichen"].ToString();
var InterimBookmarks = JsonConvert.DeserializeObject<ObservableCollection<Bookmark>>(savedLesezeichen);
foreach (var bookmark in InterimBookmarks)
{
Bookmarks.Add(new Bookmark { Novene = bookmark.Novene, Tag = bookmark.Tag, Date = bookmark.Date, IsChecked = false, ID = bookmark.ID });
}
}
Unfortunately when I make changes to the ObservableCollection after navigating to the page with Shell.Current.GoToAsync("LesezeichenPage") and then open the page about the FlyoutItem, the constructor won't fire for a second time. Hence the Json cannot be deserialised and the changes won't be visible in the ListView of the page.
I have to make the constructor fire somehow every time when opening the page, if that's possible. Seen a post with UWP about a NavigationCacheMode that can be disabled though ContentPage/TabbedPage don't have these options.
Maybe someone has another idea/approach to solve this?
I'm currently using Caliburn.Micro 2.0 for my Windows Phone 8.1 project (Universal App) and I'm having problem with conditionally cancelling page close after user clicks a MessageDialog button.
It seems that Caliburn closes page after leaving CanClose() method, not waiting for the callback which is called after async MessageDialog.
public class MyViewModel: Screen
{
public override async void CanClose(Action<bool> callback)
{
MessageDialog dlg = new MessageDialog("Close?","Confirmation");
dlg.Commands.Add(new UICommand() { Id = 0, Label = "Yes" });
dlg.Commands.Add(new UICommand() { Id = 1, Label = "No" });
var result = await dlg.ShowAsync();
callback((int)result.Id == 0);
}
}
The only solution I have at the moment is set a field with a flag indicating if the page can be closed. On the user attempt to navigate back I tell Caliburn to abort the close and I display the confirmation dialog. When I get the result I set the flag to true and navigate back manually. This causes another call to CanClose, but this time I set the callback to true and skip the dialog part.
I don't like this solution much, but it is only way I managed to solve this problem.
private bool canClose = false;
public override async void CanClose(Action<bool> callback)
{
callback(canClose);
if (!canClose)
{
MessageDialog dlg = new MessageDialog("Close?","Confirmation");
dlg.Commands.Add(new UICommand() { Id = 0, Label = "Yes" });
dlg.Commands.Add(new UICommand() { Id = 1, Label = "No" });
var result = await dlg.ShowAsync();
if ((int)result.Id == 0)
{
canClose = true;
navigationService.GoBack();
}
}
}
PS: I don't use MessageDialog directly in my ViewModel, I'm using a dialog service interface for popups. I just used it here to demonstrate the issue.
While the enhancement CanClose isn't set, this is my approach utilize Navigating event to solve this 'problem'
If user could just GoBack() would be easy to handle, but in my case, there's many options to navigate. So, the only way that I found to solve it is described below:
public MyViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
_navigationService.Navigating += OnGoBack;
}
private async void OnGoBack(object sender, NavigatingCancelEventArgs e)
{
e.Cancel = true;
var dlg = new MessageDialog("Close?", "Confirmation"); //Dialog for demo purpose only!
dlg.Commands.Add(new UICommand() { Id = 0, Label = "Yes" });
dlg.Commands.Add(new UICommand() { Id = 1, Label = "No" });
var result = await dlg.ShowAsync();
if ((int) result.Id != 0) return;
_navigationService.Navigating -= OnGoBack;
if (e.NavigationMode == NavigationMode.Back)
_navigationService.GoBack();
else
{
var myViewModel = Type.GetType($"YourNameSpaceViewModels.{e.SourcePageType.Name}Model");
_navigationService.NavigateToViewModel(myViewModel);
}
}
Explaination:
$"YourNameSpaceViewModels.{e.SourcePageType.Name}Model"
Here I get the full path to my class where user want to goto
And so, I navigate to it _navigationService.NavigateToViewModel(myViewModel);
i have a Listbox with items being 'first name' loaded from a table of a database,
now i want an autofill feature where if a user types like 'a' all the names starting with 'a' first name should be show in the listbox
and after some button click the original data should be repopulated in the listbox
for 2nd one i.e.. repopulating hope i can do with below code
protected void btnRePopulate_Click(object sender, EventArgs e)
{
DataSet oDs = ReadDataSet();
Listbox1.DataTextField = "Name";
Listbox1.DataValueField = "ID";
Listbox1.DataSource = oDs;
Listbox1.DataBind();
}
but for the 1st i have some things on which iam working (i am using textbox keyup event to fire when the user types 'a' or whatever)
clear the listbox and add the names which starts with 'a', but not sure is it possible from client side
or set another listbox visible with names filtered from the original and hide the original listbox, for which i am not able to set visible property either from js or codebehind
no i dont want to use ajax autofill
is there a better option apart from the above two...
This filtering and resetting is best done on the client side itself. That way you don't make unnecessary server calls. Here is a extension method in jQuery.
$(function() {
$('#select').filterByText($('#textbox'), true);
});
Extension method:
jQuery.fn.filterByText = function(textbox, selectSingleMatch) {
return this.each(function() {
var select = this;
var options = [];
$(select).find('option').each(function() {
options.push({value: $(this).val(), text: $(this).text()});
});
$(select).data('options', options);
$(textbox).bind('change keyup', function() {
var options = $(select).empty().scrollTop(0).data('options');
var search = $.trim($(this).val());
var regex = new RegExp(search,'gi');
$.each(options, function(i) {
var option = options[i];
if(option.text.match(regex) !== null) {
$(select).append(
$('<option>').text(option.text).val(option.value)
);
}
});
if (selectSingleMatch === true &&
$(select).children().length === 1) {
$(select).children().get(0).selected = true;
}
});
});
};
I found this on Lessan Vaezi's blog with a live demo on how to do it.
I have a dynamically generated menu (C#), like this:
MenuItem(string text, string value, string imageUrl, string navigateUrl, string target)
MenuItem AdminLevel1 = new MenuItem("Admin", "Admin"); MenuItem AdminPedidosRegisto = new MenuItem("Questions", "AdminQ");
NavigationMenu.Items.Add(new MenuItem("Messages Received", "AdminMessagesR", "", "./Admin/Messages.ascx", "ContainerIframe")); AdminPedidosRegisto.ChildItems.Add(new MenuItem("Pending", "AdminPending", "", "./Admin/Pedidos.ascx", "ContainerIframe"));
Where 'ContainerIframe' is the iFrame's ID and 'NavigationMenu' is the (asp:Menu)'s ID.
I want to disable the click action in the parent items that don't have an URL set, so the page doesn't refresh when someone clicks it.
Is there a way?
menuitem.NavigateUrl = "javascript:;";
Thanks to #Manibhadra (this is enough for parent items and child items)
window.onload = function ()
{
var menuTable = document.getElementById("<%=NavigationMenu.ClientID%>");
var menuLinks = menuTable.getElementsByTagName("a");
for (i = 0; i < menuLinks.length; i++)
{
menuLinks[i].onclick = function () { }
}
}
if (MenuItem.NavigateUrl == "")
{
MenuItem.Selectable = false;
}
I am using browseForSave() to give the user a chance to save a file before navigating back to a previous screen. As of now the cancel button on the save dialog just closes the save dialog. I want to see if the cancel button was clicked, and if so continue navigating back to the previous screen without saving. Right now the person has to save the file in order to move back. Below is the code I'm using.
public function save(e:MouseEvent):void{
if (currentFile) {
if (stream != null)
{
stream.close();
}
stream = new FileStream();
stream.openAsync(currentFile, FileMode.WRITE);
stream.addEventListener(IOErrorEvent.IO_ERROR, writeIOErrorHandler);
var str:String = mainTextField.text;
str = str.replace(/\r/g, "\n");
str = str.replace(/\n/g, File.lineEnding);
stream.writeUTFBytes(str);
stream.close();
dataChanged = false;
}
else
{
saveAs(null);
}
}
private function saveAs(event:MouseEvent):void
{
var fileChooser:File;
if (currentFile)
{
fileChooser = currentFile;
}
else
{
fileChooser = File.documentsDirectory.resolvePath('untitled.html')
}
fileChooser.browseForSave("Save As");
fileChooser.addEventListener(Event.SELECT, saveAsFileSelected);
}
If this is AIR, you could listen for the 'cancel' event. If not, I don't think you can.