I have got issues . Why did not it navigate to other xaml? Where is wrong?
So, I was trying to make it that can navigated between two or more xaml in a frame.
Here is link : https://github.com/Englbach/MutiViewInRootPage
<SplitView.Content>
<!-- OnNavigatingToPage we synchronize the selected item in the nav menu with the current page.
OnNavigatedToPage we move keyboard focus to the first item on the page after it's loaded. -->
<Frame x:Name="AppShellFrame">
<Frame.ContentTransitions>
<TransitionCollection>
<NavigationThemeTransition>
<NavigationThemeTransition.DefaultNavigationTransitionInfo>
<EntranceNavigationTransitionInfo />
</NavigationThemeTransition.DefaultNavigationTransitionInfo>
</NavigationThemeTransition>
</TransitionCollection>
</Frame.ContentTransitions>
</Frame>
</SplitView.Content>
public static AppShell Current = null;
public List<NavMenuItem> NavList { get; } = new List<NavMenuItem>(new[]
{
new NavMenuItem()
{
Symbol = Symbol.Add,
Label = "Add feed",
DestPage = typeof(RootPages),
Arguments = typeof(AddFeedView)
},
new NavMenuItem()
{
Symbol = Symbol.Edit,
Label = "Edit feeds",
DestPage = typeof(RootPages),
Arguments = typeof(EditFeedView)
}
});
public AppShell()
{
this.InitializeComponent();
Current = this;
}
private void NavMenuList_ItemInvoked(object sender, ListViewItem e)
{
NavMenuList.SelectedIndex = -1;
var item = (NavMenuItem)((NavMenuListView)sender).ItemFromContainer(e);
if(item!=null)
{
AppFrame.Navigate(typeof(RootPages), item.Arguments);
}
}
You probably followed the official Navigation menu (XAML) sample to design your layout.
There are two tiny problems in your demo.
Each time the items in the NavMenuList is clicked, the NavMenuList_ItemInvoked event in the AppShell.xaml.cs should be triggered. And in this event, you navigated again and again to your RootPages, and together pass the navigation parameter(item.Arguments) to the RootPages like this AppFrame.Navigate(typeof(RootPages), item.Arguments);, and the argument is actually your destination.
You can modify the code here like this:
private void NavMenuList_ItemInvoked(object sender, ListViewItem e)
{
//NavMenuList.SelectedIndex = -1;
var item = (NavMenuItem)((NavMenuListView)sender).ItemFromContainer(e);
if (item != null)
{
//AppFrame.Navigate(typeof(RootPages), item.Arguments);
if (item.DestPage != null &&
item.DestPage != this.AppFrame.CurrentSourcePageType)
{
this.AppFrame.Navigate(item.DestPage, item.Arguments);
}
}
}
Then here comes the second problem, as I said, the Arguments should be navigation parameter, for example, I navigate to AddFeedView page and I want to send a message "balalala", then we can code like this: AppFrame.Navigate(typeof(AddFeedView), "balalala");. This means, you confused with your DestPage and Arguments.
You can modify your NavList like this:
public List<NavMenuItem> NavList { get; } = new List<NavMenuItem>(new[]
{
new NavMenuItem()
{
Symbol = Symbol.Add,
Label = "Add feed",
DestPage = typeof(AddFeedView),
Arguments = typeof(RootPages)
},
new NavMenuItem()
{
Symbol = Symbol.Edit,
Label = "Edit feeds",
DestPage = typeof(EditFeedView),
Arguments = typeof(RootPages)
}
});
In additional, if you want your AppFrame to navigate to the RootPages at first by default, you can code like this:
public AppShell()
{
this.InitializeComponent();
Current = this;
AppFrame.Navigate(typeof(RootPages));
}
Related
I have a page with a Tab View. Inside every tab is another page. Whenever I try to interact with the tab, nothing works. I tried interacting with it with SettingsPage as the content, and it worked.
MainPage - contains the tabs
TabbedMainPage - contains the workspace
SettigsPage - contains settings
MainPage:
private void TabView_AddTabButtonClick(TabView sender, object args)
{
sender.TabItems.Add(CreateNewTab());
}
public TabViewItem OpenSettingsTab()
{
TabViewItem newItem = new TabViewItem();
newItem.Header = "Settings";
newItem.IconSource = new Microsoft.UI.Xaml.Controls.SymbolIconSource() { Symbol = Symbol.Setting };
Frame frame = new Frame();
frame.Navigate(typeof(SettingsPage));
newItem.Content = frame;
TabbedView.UpdateLayout();
return newItem;
}
public void CreateSettingsTab()
{
TabbedView.TabItems.Add(OpenSettingsTab());
TabbedView.UpdateLayout();
TabbedView.SelectedIndex = TabbedView.TabItems.Count - 1;
}
public TabViewItem CreateNewTab()
{
TabViewItem newItem = new TabViewItem();
newItem.Header = "New Tab";
newItem.IconSource = new Microsoft.UI.Xaml.Controls.SymbolIconSource() { Symbol = Symbol.Document };
Frame frame = new Frame();
frame.Navigate(typeof(TabbedMainPage));
newItem.Content = frame;
TabbedView.UpdateLayout();
return newItem;
}
private void TabbedView_Loaded(object sender, RoutedEventArgs e)
{
var S = sender as TabView;
if (S.TabItems.Count == 0)
{
S.TabItems.Add(CreateNewTab());
}
TabbedView.UpdateLayout();
}
TabbedMainPage has the following components: ColorPicker, DropDownButton, MenuBar, Border, Button, CheckBox, ComboBox, Flyout, Grid, Image, MenuFlyout, Pivot, PivotItem, StackPanel, TextBlock, TextBox, Flyout, Popup, RichEditBox, ScrollViewer, Slider, ToggleButton and Tooltip.
I think it might be caused by overloading with components, but I'm not sure. I also have these in my code:
MediaElement ME;
SpeechSynthesizer Synth;
public StorageFile TXTFile;
public IRandomAccessStream RAS;
private readonly PrintHelperOptions PP = new PrintHelperOptions();
var LS = ApplicationData.Current.LocalSettings;
var TB = ApplicationView.GetForCurrentView().TitleBar;
var CTB = CoreApplication.GetCurrentView().TitleBar;
I managed to fix the bug by removing the Pivot from the toolbar. It was interfering with the tab functionality, so I merged all the items together.
I'm trying to create a ListView Page that works for every object in my app where I can show all the objects received by parameter from a List<object> where I don't know which object the page will have to handle, I also receive the fields to show as parameters in a List <string, string> where the first string is the type of the field (header/subheader/image) and for that, I had to use XAML Reader so I could create the data bindings in the code behind.
Here's my code:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var param = (Dictionary<string, object>)e.Parameter;
_ItemsList = (List<object>)param["itemsList"];
_Fields = (Dictionary<string, string>)param["fields"];
_DetailsPage = (Type)param["detailPage"];
EditCommand = new UniversalListViewCommand();
ObjListView.ItemsSource = UniversalAutoSuggestBox.ItemsSource = _ItemsList;
MainStackPanel.DataContext = this;
ObjListView.ItemTemplate = NormalItemTemplate = (DataTemplate)XamlReader.Load(GenerateDataTemplate("NormalItemTemplate"));
SelectedItemTemplate = (DataTemplate)XamlReader.Load(GenerateDataTemplate("SelectedItemTemplate"));
}
public string GenerateDataTemplate(string param)
{
StringBuilder sbTemp = new();
//Data Template definition
if (param == "NormalItemTemplate") sbTemp.Append("<DataTemplate x:Key=\"NormalItemTemplate\" ");
if (param == "SelectedItemTemplate") sbTemp.Append("<DataTemplate x:Key=\"SelectedItemTemplate\" ");
//sbTemp.Append("x:Class = \"xizPrototipo_0_2.Pages.UniversalListViewPage\" ");
sbTemp.Append(#"xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" ");
sbTemp.Append(#"xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">");
//Grid definition
sbTemp.Append("<Grid MinWidth=\"350\" Margin=\"5\">");
//Grid row definition
sbTemp.Append("<Grid.RowDefinitions>");
sbTemp.Append("<RowDefinition Height = \"*\" />");
sbTemp.Append("<RowDefinition Height = \"*\" />");
sbTemp.Append("<RowDefinition Height = \"*\" />");
sbTemp.Append("</Grid.RowDefinitions>");
//Grid column definition
sbTemp.Append("<Grid.ColumnDefinitions>");
sbTemp.Append("<ColumnDefinition Width = \"Auto\"/>");
sbTemp.Append("<ColumnDefinition Width = \"*\" />");
sbTemp.Append("</Grid.ColumnDefinitions>");
//Ellipse definition
sbTemp.Append("<Ellipse Grid.Row=\"0\" Grid.RowSpan=\"2\" Width = \"32\" Height = \"32\" Margin = \"6\" VerticalAlignment = \"Center\" HorizontalAlignment = \"Center\">");
sbTemp.Append("<Ellipse.Fill> <ImageBrush x:Name =\"LogoImage\" ImageSource = \"{Binding " + _Fields["Image"] + "}\" /> </Ellipse.Fill> ");
sbTemp.Append("</Ellipse>");
//Header Text Block Definition
sbTemp.Append("<TextBlock Grid.Row = \"0\" Grid.Column = \"1\" Text = \"{Binding " + _Fields["Header"] + "}\" Style = \"{ThemeResource BaseTextBlockStyle}\" Margin = \"12,6,0,0\"/> ");
//Subheader Text Block Definition
sbTemp.Append("<TextBlock Grid.Row=\"1\" Grid.Column = \"1\" Text = \"{Binding " + _Fields["Subheader"] + "}\" Style = \"{ThemeResource BodyTextBlockStyle}\" Margin = \"12,0,0,6\" /> ");
//Button (case Selected)
if (param == "SelectedItemTemplate")
{
sbTemp.Append("<StackPanel Grid.Row=\"2\" Grid.Column=\"1\" Orientation =\"Horizontal\" HorizontalAlignment =\"Right\" Spacing = \"5\" > ");
sbTemp.Append("<Button x:Name=\"EditButton\" Content=\"Editar\" Click=\"AlterButton_Click\" />");
sbTemp.Append("</StackPanel>");
}
//Grid end
sbTemp.Append("</Grid>");
//DataTemplate end
sbTemp.Append("</DataTemplate>");
return sbTemp.ToString();
}
With this method I could get the outcome that I wanted but when I click the button created in the following line it don't fires any event:
sbTemp.Append("<Button x:Name=\"EditButton\" Content=\"Editar\" Click=\"AlterButton_Click\" />");
I also tried using commands, Data Template selector and still I couldn't do anything with that button.
Does anyone know how can I put that button to work?
(Yes, I have the event on the button created and a function to change the Data Template to show the button.)
Data Template Button created in XamlReader don't firing events
I am afraid it will not respond to the click event handler created from the string xaml. Because the click event registration process will be saved in the xxpage.g.cs file during pre-compilation. However, if you load the data template from the string runtime. It will not register for this event.
So the better way is binding command for button.
For example
public MainPage()
{
this.InitializeComponent();
DataTemplate itmeTemplate = (DataTemplate)XamlReader.Load(
#"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
<Button Command='{Binding BtnClickCommand}' Content='Editor' />
</DataTemplate>");
TestListView.ItemTemplate = itmeTemplate;
NumbersList = new ObservableCollection<Item>();
for (int i = 0; i < 50; i++)
{
var item = new Item ();
NumbersList.Add(item);
}
TestListView.ItemsSource = NumbersList;
}
public ObservableCollection<Item> NumbersList { get; set; }
Model
public class Item : INotifyPropertyChanged
{
public ICommand BtnClickCommand
{
get
{
return new RelayCommand(() =>
{
});
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
// Raise the PropertyChanged event, passing the name of the property whose value has changed.
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Xaml Code
<Grid x:Name="RootGrid">
<ListView
x:Name="TestListView"
ItemsSource="{x:Bind NumbersList}"
Visibility="Visible">
</ListView>
</Grid>
Update 1
public MainPage()
{
this.InitializeComponent();
this.DataContext = this;
DataTemplate itmeTemplate = (DataTemplate)XamlReader.Load(
#"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
<Button Command='{Binding DataContext.BtnClickCommand, ElementName=TestListView}' Content='Editor' />
</DataTemplate>");
TestListView.ItemTemplate = itmeTemplate;
NumbersList = new ObservableCollection<Item>();
for (int i = 0; i < 50; i++)
{
var item = new Item ();
NumbersList.Add(item);
}
TestListView.ItemsSource = NumbersList;
}
public ICommand BtnClickCommand
{
get
{
return new RelayCommand(async () =>
{
});
}
}
I have a NavigationView and some NavigationViewItems generated in code behind.
From the code I was trying to select one NavigationViewItem that was the default one showed to the user at launch and I expirienced a strange behavior
(this behavior doesn't happen if you select a NavigationViewItem that was generated in the xaml).
When I launch the app I can't see the selection (the accent colored rectangle on the left of the NavigationViewItem) but when I click another NavigationViewItem the rectangle shows up and start the animation that moves it from the old NavigationViewItem to the new one.
I followed the same code that I found on the documentation with the exception that in the documentation they select a NavigationViewItem that was generated in the xaml.
https://learn.microsoft.com/en-us/windows/uwp/design/controls-and-patterns/navigationview
Here is the code to reproduce the problem (minimum version and target version of the project: Win10 FCU Build 16299)
XAML:
<NavigationView x:Name="navView" Loaded="navView_Loaded">
</NavigationView>
<Button Content="Select Mail" Click="button_Click" HorizontalAlignment="Center"/>
c#:
private void navView_Loaded(object sender, RoutedEventArgs e)
{
navView.MenuItems.Add(new NavigationViewItem()
{ Content = "Home", Icon = new SymbolIcon(Symbol.Home), Tag = "home" });
navView.MenuItems.Add(new NavigationViewItem()
{ Content = "My content", Icon = new SymbolIcon(Symbol.Folder), Tag = "content" });
navView.MenuItems.Add(new NavigationViewItem()
{ Content = "Mail", Icon = new SymbolIcon(Symbol.Mail), Tag = "mail" });
foreach (NavigationViewItemBase item in navView.MenuItems)
{
if (item is NavigationViewItem && item.Tag.ToString() == "home")
{
navView.SelectedItem = item;
break;
}
}
}
private void button_Click(object sender, RoutedEventArgs e)
{
navView.SelectedItem = navView.MenuItems.ElementAt(2);
}
The problem is that you have do more things in the navView_Loaded cause SelectionIndicator animation terminate. You could add await Task.Delay(500); before setting NavigationView selectedItem to verify this.
await Task.Delay(500);
foreach (NavigationViewItemBase item in navView.MenuItems)
{
if (item is NavigationViewItem && item.Tag.ToString() == "home")
{
navView.SelectedItem = item;
(navView.SelectedItem as NavigationViewItem).IsSelected = true;
break;
}
}
For your scenario, you could add the MenuItems in the Loading event handler method and set the select item in the Loaded event handler method.
private void navView_Loaded(object sender, RoutedEventArgs e)
{
foreach (NavigationViewItemBase item in navView.MenuItems)
{
if (item is NavigationViewItem && item.Tag.ToString() == "home")
{
navView.SelectedItem = item;
(navView.SelectedItem as NavigationViewItem).IsSelected = true;
break;
}
}
}
private void navView_Loading(FrameworkElement sender, object args)
{
navView.MenuItems.Add(new NavigationViewItem()
{ Content = "Home", Icon = new SymbolIcon(Symbol.Home), Tag = "home" });
navView.MenuItems.Add(new NavigationViewItem()
{ Content = "My content", Icon = new SymbolIcon(Symbol.Folder), Tag = "content" });
navView.MenuItems.Add(new NavigationViewItem()
{ Content = "Mail", Icon = new SymbolIcon(Symbol.Mail), Tag = "mail" });
}
I have a multiple ViewCell and ImageCell subclasses inside a TableView.
I would like to execute some code when the user taps the cell. The whole cell highlights whenever it's touched, but I don't see any event handler to use here.
Isn't there a XAML Tapped equivalent for this but in code only?
private void SetTableView()
{
Content = new TableView
{
HasUnevenRows = true,
Intent = TableIntent.Menu,
Root = new TableRoot()
{
new TableSection()
{
new ProfileCell(ImageSource.FromFile("profile_placeholder.png"), "Casa de Férias")
},
new TableSection()
{
new InfoCell()
{
Type = InfoCellTypes.Pending,
Text = "Avaliação do Imóvel",
Detail = "Estado do Processo"
}
}
}
};
}
I'm sure there must be some API that handles this. Maybe I'm just not looking in the right place?
Thank you!
This can be accomplished by adding a TapGestureRecognizer to the cell's view layout.
var absoluteLayout = new AbsoluteLayout
{
Children =
{
photo,
editImage,
label
}
};
var tapGestureRecognizer = new TapGestureRecognizer();
tapGestureRecognizer.NumberOfTapsRequired = 1;
tapGestureRecognizer.Tapped += (s, e) => {
// handle the tap
};
absoluteLayout.GestureRecognizers.Add(tapGestureRecognizer);
View = absoluteLayout;
EDIT:
Or, a better alternative, using the Tapped property of the ViewCell, so it doesn't break the "Tap Animation":
Tapped += new EventHandler((e, s) => {
if (command.CanExecute(null))
{
command.Execute(null);
}
});
While learning how to use Xamarin Forms and StackLayouts I'm having trouble rendering the items.
I'm trying to bind a collection of somethings to a StackLayout. The binding (more or less) works. The visual render is wrong.
For this question, I've picked some random thing (in this case, credit cards) to highlight my experimenting.
This is what I'm rending:
Notice how each custom row looks to be fixed height's or something?
Show me the code! Ok, so this is what I've done:
First, the page:
public class MyPage : ContentPage
{
protected override void OnAppearing()
{
var creditCards = new SomeFakeListOfCreditCards();
var stackLayout = new CreditCardStackLayout(creditCards);
Contet = stackLayout;
}
}
Now for the custom control...
public class CreditCardStackLayout : StackLayout
{
public CreditCardStackLayout(IEnumerable<CreditCard> creditCards)
{
// Note: credit cards can be null (because we don't have any).
CreateContent(creditCards);
}
private void CreateContent(IEnumerable<CreditCard> creditCards)
{
VerticalOptions = LayoutOptions.Center;
Children.Add(TitleLabel);
if (creditCards == null)
{
Children.Add(NoCreditCardLabel);
}
else
{
Children.Add(CreateCreateCardList(creditCards));
}
}
private static ListView CreateCreateCardList(IEnumerable<CreditCard> creditCards)
{
if (creditCards == null)
{
throw new ArgumentNullException("creditCards");
}
// Project the credit cards into a list view model.
var viewModel = creditCards.Select(x => new CreditCardViewModel(x));
return new ListView
{
ItemsSource = viewModel,
ItemTemplate = new DataTemplate(typeof(CreditCardViewCell))
};
}
private Label TitleLabel
{
get
{
return new Label
{
HorizontalOptions = LayoutOptions.Center,
Text = "A list of credit cards"
};
}
}
private Label NoCreditCardLabel
{
get
{
return new Label
{
Text = "You have no real credit cards on file."
};
}
}
}
So far so good.. Now for the binding..
public class CreditCardViewCell : ViewCell
{
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
var stackLayout = new StackLayout
{
BackgroundColor = new Color(46, 81, 163),
VerticalOptions = LayoutOptions.Center,
Children =
{
NameLabel,
TypeImage,
NumberLabel,
ExpiresOnLabel,
RemoveButton
}
};
View = stackLayout;
}
private Label NameLabel
{
get
{
var label = new Label
{
FontSize = 14
};
label.SetBinding(Label.TextProperty, "Name");
return label;
}
}
private Label NumberLabel
{
get
{
var label = new Label
{
FontSize = 14
};
label.SetBinding(Label.TextProperty, "Number");
return label;
}
}
private Label ExpiresOnLabel
{
get
{
var label = new Label
{
FontSize = 14
};
label.SetBinding(Label.TextProperty, "ExpiresOn");
return label;
}
}
private Image TypeImage
{
get
{
var creditCardModel = (CreditCardViewModel)BindingContext;
string fileName = null;
switch (creditCardModel.Type)
{
case "Visa":
fileName = "visa.png";
break;
default:
fileName = "mastercard.png";
break;
}
var image = new Image
{
Source = ImageSource.FromFile("Icons/" + fileName)
};
return image;
}
}
private Button RemoveButton
{
get
{
var button = new Button
{
//Image = "Icons/remove.png"
Text = "Remove"
};
button.Clicked += async (object sender, EventArgs e) =>
{
// TODO when I figure out how to do this stuff.
int i = 0;
i++;
};
return button;
}
}
}
}
Also, please do not suggest going to a XAML file, I'm trying to learn this stuff programmatically.
Side thought: I wish I could turn on borders so I can see how things are laid out.
Use ListView's HasUnevenRows property. Change this:
return new ListView
{
ItemsSource = viewModel,
ItemTemplate = new DataTemplate(typeof(CreditCardViewCell))
};
to:
return new ListView
{
HasUnevenRows = true,
ItemsSource = viewModel,
ItemTemplate = new DataTemplate(typeof(CreditCardViewCell))
};
By default Xamarin.Forms ListView row size is fixed and set to the same value for every row (RowHeight property). With this configuration row auto-sizing won't work, but it also gives best ListView performance.
You can auto-size rows by setting ListView's HasUnevenRows property to true. It allows modifying ViewCell size by setting ViewCell's RowHeight property (eg. in OnBindingContextChanged override). In newer Xamarin.Forms versions it also sizes ViewCells automatically (on older it worked only on Android).