I'm new to UWP and I have what I think is a simple problem to solve, but the examples I've found haven't worked. I'm using a navigation view in UWP project and I want to be able to switch page and display in a frame. When I select an item in the navigation view the ItemInvoked event is fired. I know the code to load the page into the frame which I've included below.
void enVigilServer::MainPage::nvSample_ItemInvoked(Windows::UI::Xaml::Controls::NavigationView^ sender, Windows::UI::Xaml::Controls::NavigationViewItemInvokedEventArgs^ args)
{
this->contentFrame->Navigate(Windows::UI::Xaml::Interop::TypeName(SysConf::typeid));
}
My problem is how to determine which item I've selected from the NavigationView to show the relevant page.
Thanks
It's actually related to c++-cx and I will purpose this tag to your issue.
To make the navigation simple we can use the tag system in our app. See the following code:
<NavigationView x:Name="NavigationViewControl" ItemInvoked="NavigationViewControl_ItemInvoked" >
<NavigationView.MenuItems>
<NavigationViewItem Content="A" x:Name="A" Tag="tga" />
<NavigationViewItem Content="B" x:Name="B" Tag="tgb"/>
<NavigationViewItem Content="C" x:Name="C" />
</NavigationView.MenuItems>
<Frame x:Name="contentFrame"/>
</NavigationView>
This is an example, we will add tags to our items. Then we will do the following in our invoke code:
void NavigationVWCX::MainPage::NavigationViewControl_ItemInvoked(Windows::UI::Xaml::Controls::NavigationView^ sender, Windows::UI::Xaml::Controls::NavigationViewItemInvokedEventArgs^ args)
{
auto navitemtag = args->InvokedItemContainer->Tag->ToString();
if (navitemtag == "tga")
{
contentFrame->Navigate(Windows::UI::Xaml::Interop::TypeName(PageA::typeid));
}
if (navitemtag == "tgb")
{
contentFrame->Navigate(Windows::UI::Xaml::Interop::TypeName(PageB::typeid));
}
}
BTW, don't forget to also add tag to your pages, like:
PageB::PageB()
{
InitializeComponent();
this->Tag = "tgb";
}
Related
I have just updated my code to use the latest 2.4.0-alpha05 for the navigation component and I have custom navigation between the multiple stacks and my main nav graph is like the documentation I found.
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:startDestination="#+id/accounts"
android:id="#+id/bottom_nav">
<inclue app:graph="#navigation/accounts_tab_nav"/>
<include app:graph="#navigation/contact_tab_nav" />
<include app:graph="#navigation/profile_tab_nav" />
</navigation>
Most of my stacks animate with a slide from right to left. It looks like that when I am on the second screen, in let's say the profile screen, and then switch to the first tab it triggers the popEnter en popExitAnim that are defined in the action that leads to the second screen in the profile tab. Like so:
<fragment
android:id="#+id/profileMain"
android:name="com.app.ProfileFragment"
tools:layout="#layout/fragment_profile">
<action
android:id="#+id/action_profileMain_to_secondFragment"
app:destination="#id/secondFragment"
app:enterAnim="#anim/slide_in_right"
app:exitAnim="#anim/slide_out_left"
app:popEnterAnim="#anim/slide_in_left"
app:popExitAnim="#anim/slide_out_right" />
</fragment>
But obviously I want tho use the (default) fade animation when switching tabs. So how should I do that?
And I would like to pop to the root of the stack when reselecting a tab. But I probably have to do that myself?
I came up with a solution that seems to work for me, but I have to admit it feels a little bit hacky.
I have a public flag in my MainActivity:
var tabWasSelected = false
Then I remember if a tab item was selected in setOnItemSelectedListener
// always show selected Bottom Navigation item as selected (return true)
bottomNavigationView.setOnItemSelectedListener { item ->
// In order to get the expected behavior, you have to call default Navigation method manually
NavigationUI.onNavDestinationSelected(item, navController)
// set flag so that the fragment can call the correct animation on tab change in onCreateAnimation
tabWasSelected = true
return#setOnItemSelectedListener true
}
This will always select the item and navigate to the associated destination while maintaining multiple back stacks.
I then have created a Fragment class which all my other fragments inherit from. It simply overrides onCreateAnimation to set the correct animation. Here is what it looks like:
open class MyFragment: Fragment() {
override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {
val activity = requireActivity()
if (activity is MainActivity) {
if (activity.tabWasSelected) {
if (enter) {
//flow is exit first, then enter, so we have to reset the flag on enter
//in order that following animations will run as defined in the nav graph
activity.tabWasSelected = false
return AnimationUtils.loadAnimation(requireContext(), R.anim.nav_default_pop_enter_anim)
} else {
return AnimationUtils.loadAnimation(requireContext(), R.anim.nav_default_pop_exit_anim)
}
}
}
//no tab was selected, so run the defined animation
return super.onCreateAnimation(transit, enter, nextAnim)
}
}
Instead of using setupWithNavController function, follow this way.
First, create your NavOptions which include animation shown below.
val options = NavOptions.Builder()
.setLaunchSingleTop(true)
.setEnterAnim(R.anim.enter_from_bottom)
.setExitAnim(R.anim.exit_to_top)
.setPopEnterAnim(R.anim.enter_from_top)
.setPopExitAnim(R.anim.exit_to_bottom)
.setPopUpTo(navController.graph.startDestination,false)
.build();
Then use setOnNavigationItemSelectedListener to navigate with animation like that.
bottomNavigationView.setOnNavigationItemSelectedListener
{ item ->
when(item.itemId) {
R.id.fragmentFirst -> {
navController.navigate(R.id.fragmentFirst,null,options)
}
R.id.fragmentSecond -> {
navigate(R.id.fragmentSecond,null,options)
}
R.id.fragmentThird -> {
navController.navigate(R.id.fragmentThird,null,options)
}
}
}
Finally, you should prevent same item selection case so you can add below code.
bottomNavigationView.setOnNavigationItemReselectedListener
{ item ->
return#setOnNavigationItemReselectedListener
}
I used bottomNavigation like that in my project to add animation for page transitions. I hope it helped.
I have created a custom ribbon button following the steps mentioned in http://jondjones.com/how-to-add-a-custom-sitecore-button-to-the-editor-ribbon/
I can see the button appearing in sitecore:
Custom button
Command does not get triggered when clicked on the button.
Below is my code:
using System;
using Sitecore.Shell.Applications.Dialogs.ProgressBoxes;
using Sitecore.Shell.Framework.Commands;
namespace SitecoreVsPoc.Commands
{
public class TranslateContent : Command
{
private static readonly object Monitor = new object();
public override void Execute(CommandContext context)
{
if (context == null)
return;
try
{
ProgressBox.Execute("Arjun", "Title", "Applications/32x32/refresh.png", Refresh);
}
catch (Exception ex)
{
Sitecore.Diagnostics.Log.Error("Error!", ex, this);
}
}
public void Refresh(params object[] parameters)
{
// Do Stuff
}
}
}
Below is the command I have registered in commands.config:
<command name="contenteditor:translatecontent" type="SitecoreVsPoc.Commands.TranslateContent,SitecoreVsPoc" />
Note: I am using Sitecore 8.2 initial release.
Can someone suggest a solution for this?
In Sitecore 8 it was changed the way you add Ribbon button. As far I see your link is from Sitecore 7 or 6.
To create the new button item for the Experience Editor ribbon:
In the Core database, open the Content Editor and navigate to /sitecore/content/Applications/WebEdit/Ribbons/WebEdit/Page Editor/Edit.
Create a new item based on the relevant ribbon control template, for example, the Small Button template. The templates are located at /sitecore/templates/System/Ribbon/.
For the new item, add the following information:
In the Header field, enter the display name of the button.
In the ID field, enter a unique identifier for the item. For example, you can include the ribbon group name in the ID.
In the Icon field, enter the path to the relevant icon. Depending on the button you create, adjust the icon size accordingly.
Open Sitecore Rocks and add the relevant control rendering, for example SmallButton, to the layout of the button item you created.
Enter a unique ID for the rendering.
For other SPEAK controls, you can point to another item in the Data Source field and specify the configuration in this other item.
Important
More informations you can find here: https://doc.sitecore.net/sitecore_experience_platform/content_authoring/the_editing_tools/the_experience_editor/customize_the_experience_editor_ribbon
http://reyrahadian.com/2015/04/15/sitecore-8-adding-edit-meta-data-button-in-experience-editor/
Before it was very simple, you didn't need to add new code:
https://blog.istern.dk/2012/05/21/running-sitecore-field-editor-from-a-command/
I create a simple demo site for DMS function of Sitecore.
In sitecore content, I created this structure:
Home
|-Personalize
..|-HomeView1
..|-HomeView2
HomeView1, HomeView2 and Home have the same template, which contains only one Field: Display Text
Now I create Personalize for home page, set rule for it.
The rule is current month is August and point the Personalize Content to HomeView1.
When I do preview the content doesn't change into text of HomeView1.
Here is my source code:
public partial class HomePage : System.Web.UI.UserControl
{
protected Item currentItem;
protected void Page_Load(object sender, EventArgs e)
{
currentItem = Sitecore.Context.Item;
}
}
And this what I bound on Home page
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="HomePage.ascx.cs" Inherits="DMSDemo.sublayouts.HomePage" %>
<div><%= currentItem["Display Text"].ToString() %></div>
I wonder why Sitecore.Context.Item will not return the correct item (HomeView2) when the personalize rule is applied?
Please give me some advise. Thanks in advance.
The context item doesn't change when you personalize, the sublayout's datasource does. So you should set currentItem to the datasource.
Here's some common code to get the datasource which I copy/pasted from Matthew Dresser's blog:
var sublayout = this.Parent as Sitecore.Web.UI.WebControls.Sublayout;
if (sublayout != null)
{
Guid dataSourceId;
Sitecore.Data.Items.Item dataSource;
if (Guid.TryParse(sublayout.DataSource, out dataSourceId))
{
dataSource = Sitecore.Context.Database.GetItem(new ID(dataSourceId));
}
else
{
dataSource = Sitecore.Context.Database.GetItem(sublayout.DataSource);
}
}
Some other points:
In general, it's good practice to avoid the use of the context
item
There is no requirement for your page item (Home) to be the
same template has the datasource items.
I don't think personalization
works in preview mode, but you can check it in edit mode.
I want to be able to right click on a content item in Sitecore and then select something like "Run My App" in the context menu. Then in the app that runs I need to be able to reference the content item that was right clicked. Is this possible?
Yes you can do this, its not as hard as it sounds.
You want to drop into the Core database and open up the content editor. The right click menu is defined within the sitecore/content/Applications/Content Editor/Context Menus/Default
The items within that folder are what you see when you right-click an item in the tree. So you can add a new item there with a template of Menu Item.
If you look at the existing ones, most of them send a message to the Sitecore Desktop. These messages are the commands defined in /App_Config/Commands.config. I can't see anything in there that would just launch another Sitecore application, so you would need to create a new command to do that. To create one, just inherit from the Sitecore.Shell.Framework.Commands.Command class. That passes in a CommandContext which will holds a collection of Items.
public class DemoCommand: Command
{
#region Overrides of Command
/// <summary>
/// Executes the command in the specified context.
/// </summary>
/// <param name="context">The context.</param>
public override void Execute(CommandContext context)
{
Assert.ArgumentNotNull(context, "context");
var parameters = new NameValueCollection();
if (context.Items != null && context.Items.Length == 1)
{
var item = context.Items[0];
parameters["id"] = item.ID.ToString();
}
Context.ClientPage.Start(this, "Run", parameters);
}
#endregion
public CommandState QueryStat(CommandContext context)
{
Assert.ArgumentNotNull(context, "context");
return CommandState.Enabled;
}
protected static void Run(ClientPipelineArgs args)
{
Assert.ArgumentNotNull(args, "args");
SheerResponse.CheckModified(false);
SheerResponse.Broadcast(
SheerResponse.ShowModalDialog(
"[Path to your application here]"
),
"Shell");
}
}
To get the item passed over, in your message call - just pass the variable $Target.
So the field Message in the Menu Item would be something like:
item:runMyApplication(id=$Target)
Hope that makes sense :)
I'm working on a project that uses a master page and content pages. My masterpage a navigation bar:
<asp:Menu ID="NavigationMenu" runat="server" CssClass="menu" EnableViewState="false" IncludeStyleBlock="false" Orientation="Horizontal">
<Items>
<asp:MenuItem NavigateUrl="~/ProjectPage.aspx" Text="Home" />
<asp:MenuItem NavigateUrl="~/ProductBacklog.aspx" Text="Product Backlog"/>
<asp:MenuItem NavigateUrl="~/SprintBacklog.aspx" Text="Sprint Backlog" />
<asp:MenuItem NavigateUrl="~/MeetingPage.aspx" Text="Meetings" />
<asp:MenuItem NavigateUrl="~/Burndown.aspx" Text="Burndown"/>
<asp:MenuItem NavigateUrl="~/About.aspx" Text="About Us"/>
</Items>
</asp:Menu>
On one of my content pages, I dynamically add sub-menu menuitems to my 'Sprint Backlog' menuitem. There is a button, and everytime the user clicks that button, a sub-menuitem is added, so that when the user hovers over 'Sprint Backlog' in the navigation menu, the submenu comes up. I do this by creating a list of menuitems, creating a new menuitem with (shown text, value, navigationURL), adding the menuitem to the list of menuitems, then saving the list to Session:
protected void btSave_Click(object sender, EventArgs e)
{
menuItemList = (List<MenuItem>)Session["menuItemList"];
if (menuItemList == null)
{
menuItemList = new List<MenuItem>();
}
MenuItem menuItem = new MenuItem("Sprint " + sprintNumber, sprintNumber.ToString(), "SprintBacklog.aspx");
menuItemList.Add(menuItem);
Session["menuItemList"] = menuItemList;
}
In the code-behind for my masterpage, I create a list of menuitems, set the value of the instance of the menuitem from Session, and add childitems to the navigationmenu at the appropriate index. The childitem I am adding are the menuitems from the list of menuitems.
List<MenuItem> menuItemList;
protected void Page_Load(object sender, EventArgs e)
{
menuItemList = (List<MenuItem>)Session["menuItemList"];
if (menuItemList != null)
{
foreach (MenuItem menuitem in menuItemList)
{
NavigationMenu.Items[2].ChildItems.Add(menuitem);
}
}
}
I know that I gave these childitems a value when I created them, but my problem is accessing those values when I am loading the SprintBacklog.aspx content page. Whenever a user clicks on one of the childitems, it will always navigate to SprintBacklog.aspx, but the contents of that page should differ according to which child item they clicked. I need a way to know which childitem they clicked, and access that value to populate my content page.
If someone has a better way for me to carry this whole thing out, I am open for suggestions and change. Otherwise, if my setup can work, and there is a way for me to extract the value of the clicked childitem, I'd really like to know that.
I know if I hard-code the childitems in my masterpage, I can easily get the value, but my problem is that I'm creating the submenu childitems dynamically, and I'm not sure how to access it.
Any help would be really appreciated! Thanks!
-Jose
It's been a long time since I asked this question, and I'm not familiar with how masterpages work anymore, but if anyone is experiencing anything similar, I may have a suggestion.
Each menu item I was creating was linking to SprintBacklog.aspx like so:
MenuItem menuItem = new MenuItem("Sprint " + sprintNumber, sprintNumber.ToString(), "SprintBacklog.aspx");
What I should have done was link to SprintBacklog.aspx, but also add a parameter to the request with the sprint ID.
Then the controller which handles the rendering of SprintBacklog.aspx would read the parameter and fetch the appropriate data to render.