How to access Child Context in UWP Frame? - c#

Can you tell me How to access Child Context in UWP Frame??
(I'm using Frame Control. (MyFrame is Frame Control)
public sealed partial class MyPage: Page
{
public MyPage()
{
this.InitializeComponent();
MyFrame.Navigate(typeof(Pages.ChildPage));
}
}
so, how to access the context of 'Pages.ChildPage'??
for example,
Pages.ChildPage.iTestVariable = 1;
Pages.ChildPage.doTestFunction();

You can access the child page after navigation like this:
var childPage = MyFrame.Content as Pages.ChildPage;
if ( childPage != null )
{
childPage.doTestFunction();
}
Of course, it is necessary to keep in mind that you can access only public methods and properties from outside the class itself.

Related

Cast Page for accessing textbox/object of other page

Previously, I had only one xaml-file, which was the only Windows, namely the mainWindow.
To access any button / textbox / object from another class (explicetly a non-static class) I can just cast the Window like this
mainWindow mainWin = Application.Current.Windows.Cast<Window>().FirstOrDefault(w => w is mainWindow) as mainWindow;
Now my question is, how does this work for several pages, since now I have a Frame, where I load several pages to.
Actually it does NOT work like this:
myPage page = Application.Current.Windows.Cast<Page>().FirstOrDefault(p => p is myPage) as myPage;
There is a runtime-error, which says:
System.InvalidCastException: Object of type "namespace.mainWindows" cannot be converted to object of type "System.Windows.Controls.Page"
make MainWindow return a Page, which is displayed:
public class mainWindow
{
public Page GetCurrentPage()
{
// return known Page;
};
}
and then:
mainWindow mainWin = Application.Current.Windows.OfType<mainWindow>().FirstOrDefault();
Page p = mainWin?.GetCurrentPage();
This one worked out for me:
MainWindow
namespace myName
{
public partial class main : Window
{
public main()
{
// ...
}
}
}
Textbox and Frame, where the page is load into, in the xaml-file of the mainWindow
Note, the FieldModifier is set to public!
<TextBox x:Name="textbox_main" Text="testString main" x:FieldModifier="public"/>
<Frame x:Name="myFrame" x:FieldModifier="public"/>
Page
namespace myName
{
public partial class myPage : Page
{
public myPage()
{
// ...
}
}
}
Textbox in the xaml-file of the Page
Note, the FieldModifier is set to public!
<TextBox x:Name="textbox_page" Text="testString page" x:FieldModifier="public"/>
After that, one is able to access the two textboxes (one directly in the window, one in a page of the window) in any other class via the following commands:
// get instance of the main-Window
main mainWin = Application.Current.Windows.Cast<Window>().FirstOrDefault(w => w is main) as main;
// Access objects of the main-Window
Console.WriteLine(mainWin.textbox_main.Text);
// get instance of the current page of the certain frame
myPage page = (myPage)Application.Current.Windows.OfType<main>().FirstOrDefault().myFrame.Content;
// Access objects of the page
Console.WriteLine(page.textbox_page.Text);

How to access a MainWindow variable from a page in C# WPF?

I am trying to code a WPF desktop Application. Currently i have a Main Window (MainWindow) and a page (Pageone) under the same solution. From my MainWindow.xaml.cs page, i have a variable (proc1) which i want to pass to my Pageone.xaml.cs page and maybe even more pages in the future to access and use for some calculation.
However i cant seem to find a method to successfully do this, i have tried making my variable "public", and instantiate the MainWindow object for my page to access it but it doesn't seem to work. (A field initializer cannot reference the non-static field, method, or property 'Pageone.pog')
MainWindow.xaml.cs
public string proc1;
public void startTroubleshootButton_Click(object sender, RoutedEventArgs e)
{
try
{
var selectedProcess = listViewProcesses.SelectedItems[0] as myProcess;
if (selectedProcess == null)
{
MessageBox.Show("no selection made");
return;
}
proc1 = selectedProcess.processName;
MessageBox.Show($"you have selected the {proc1} application ");
Pageone pg = new Pageone(this);
this.Content = pg;
}
catch(ArgumentOutOfRangeException)
{
return;
}
}
Pageone.xaml.cs
public partial class Pageone : Page
{
public Pageone(MainWindow mainWindow)
{
InitializeComponent();
}
MainWindow pog = new MainWindow();
string procName = pog.proc1;
...
I've heard that i will maybe need to use something called the MVVM or code a parameterized constructor but i'm not sure if its related to the code i'm doing. Is there a better way to go about coding this? Thanks.
It can be done like:
var window = (MainWindow)Application.Current.MainWindow;

Advice on Views navigation using Caliburn.Micro MVVM WPF

I'm new on Caliburn Micro and want some advice on which path to take to devolop my app interface and navigation between views.
My idea is to have a MainWindow which will contain a menu of buttons, each one related with a specific view. Each view will be stored in a separated WPF UserControl. The mainWindow will also contain a TabControl bound to an ObservableCollection of tabs on viewmodel. Everytime a button on menu is clicked, I want to add a new tab with a ContentPresenter inside that will dynamically load a view and its corresponding viewmodel.
So my questions:
1) Should I use a Screen Collection here?
2) Should the UserControl implement Screen interface?
3) How do I tell MainWindow ViewModel which view to load on the new added tab maintaining viewmodels decoupled?
Thanks to everyone in advance.
UPDATE
After a lot of reading and some help of the community I managed to resolve this. This is the resultant AppViewModel:
class AppViewModel : Conductor<IScreen>.Collection.OneActive
{
public void OpenTab(Type TipoVista)
{
bool bFound = false;
Screen myScreen = (Screen)Activator.CreateInstance(TipoVista as Type);
myScreen.DisplayName = myScreen.ToString();
foreach(Screen miItem in Items)
{
if (miItem.ToString() == myScreen.ToString())
{
bFound = true;
ActivateItem(miItem);
}
}
if (!bFound) ActivateItem(myScreen);
}
public ObservableCollection<MenuItem> myMenu { get; set; }
public ObservableCollection<LinksItem> myDirectLinks { get; set; }
public ICommand OpenTabCommand
{
get
{
return new RelayCommand(param => this.OpenTab((Type) param), null);
}
}
public AppViewModel()
{
OpenTab(typeof(ClientsViewModel));
MenuModel menu = new MenuModel();
myMenu = menu.getMenu();
myDirectLinks = menu.getLinks();
}
public void CloseTab(Screen param)
{
DeactivateItem(param, true);
}
}
I have to keep the ICommand from OpenTabCommand because the name convention of Caliburn.micro doesn't seems to work inside DataTemplate. Hope it could help someone else. Thanks to all
I've done something very similar using Caliburn.Micro, and based it on the SimpleMDI example included with the examples, with a few tweaks to fit my needs.
Much like in the example, I had a main ShellViewModel:
public class ShellViewModel : Conductor<IScreen>.Collection.OneActive
{
}
with a corresponding ShellView containing a TabControl - <TabControl x:Name="Items">, binding it to the Items property of the the Conductor.
In this particular case, I also had a ContextMenu on my ShellView, bound (using the Caliburn.Micro conventions), to a series of commands which instantiated and Activated various other ViewModels (usually with a corresponding UserControl, using the ActivateItem method on the Conductor.
public class YourViewModel: Conductor<IScreen>.Collection.OneActive
{
// ...
public void OpenItemBrowser()
{
// Create your new ViewModel instance here, or obtain existing instance.
// ActivateItem(instance)
}
}
In that case, I didn't require the ViewModels to be created with any particular dependency, or from any other locations in the program.
At other times, when I've needed to trigger ViewModel from elsewhere in the application, I've used the Caliburn.Micro EventAggregator to publish custom events (e.g. OpenNewBrowser), which can be handled by classes implementing the corresponding interface (e.g. IHandle<OpenNewBrowser>), so your main ViewModel could have a simple Handle method responsible for opening the required View:
public class YourViewModel: Conductor<IScreen>.Collection.OneActive, IHandle<OpenNewBrowser>
{
// ...
public void Handle(OpenNewBrowser myEvent)
{
// Create your new ViewModel instance here, or obtain existing instance.
// ActivateItem(instance)
}
}
This section of the documentation will probably be useful, especially the Simple MDI section.
Additional code I mentioned in the comments:
I sometimes use a generic method along these lines ensure that if I have an existing instance of a screen of a particular type, switch to it, or create a new instance if not.
public void ActivateOrOpen<T>() where T : Screen
{
var currentItem = this.Items.FirstOrDefault(x => x.GetType() == typeof(T));
if (currentItem != null)
{
ActivateItem(currentItem);
}
else
{
ActivateItem(Activator.CreateInstance<T>());
}
}
Used like:
public void OpenBrowser()
{
this.ActivateOrOpen<BrowserViewModel>();
}

Nested Master Pages and Inheritance

I created a nested master page. The parent master page A inherits from System.Web.UI.MasterPage. The child master page B inherits from A.
I then created a web content page C which uses master page B, and inherits from System.Web.UI.Page.
From the web content page C I am able to access variables and methods from within both master pages. However the problem lies in accessing the parent master page variables and methods.
The problem is that a NullReferenceException is being raised. Variables and methods are not being initialised.
What is a possible solution?
public partial class ParentMasterPage : System.Web.UI.MasterPage
{
internal Button btn_Parent
{
get { return btn; }
}
}
public partial class ChildMasterPage : ParentMasterPage
{
internal Button btn_Child
{
get { return btn; }
}
}
public partial class WebContentPage : System.Web.UI.Page
{
protected override void OnInit(EventArgs e)
{
Button tempA = Master.btn_Child; //WORKS
Button tempB = Master.btn_Parent; //NULL REFERENCE EXCEPTION
}
}
A nested master page does not inherit it's parent master page's type. Instead it composes itself such that the NestedMasterType.Master property is an instance of the parent master page. The NestedMasterType type still inherits from System.Web.UI.MasterPage.
So this is right:
public partial class ChildMasterPage : System.Web.UI.MasterPage
This is wrong:
public partial class ChildMasterPage : ParentMasterPage
You would then access the (parent) Master of the (child) Master of a Page (that uses the child master) like this:
Button tempA = ((ChildMasterPage)this.Master).btn_Child;
Button tempB = ((ParentMasterPage)this.Master.Master).btn_Parent;
Note: This answer assumes that you mean that ChildMasterPage is a nested master page, that uses a Master directive similar to the below:
<%# Master MasterPageFile="~/ParentMasterPage.Master" Inherits="ChildMasterPage"...
A Page only has a reference to it's immediate master and it's variables, you would have to traverse up the object graph to the main master page i.e.
var parentMaster = (ParentMasterPage)Page.Master.Master;
parentMaster.SomeProperty = ...;
Alternatively, you could bridge the gap between the 2 by implementing the same property in your ChildMasterPage i.e.
internal Button btn_Parent
{
get { return ((ParentMasterPage)Master).btn_Parent; }
}
This would mean the code you currently have would work, however, it sort of defeats the purpose of having a main master page.

Accessing different Masterpages from Base Class

I have an application that uses 2 master pages. One for main pages and one for Popup pages. These both inherit from Masterpages
public partial class MainMasterPage : System.Web.UI.MasterPage
{
UserBO objUser = null;
public UserBO GetCurrentUser()
{
UserBO userBO = new UserBO();
.....
.....
return userBO;
}
}
public partial class PopupMasterPage : System.Web.UI.MasterPage
{
UserBO objUser = null;
public UserBO GetCurrentUser()
{
UserBO userBO = new UserBO();
.....
.....
return userBO;
}
}
So far so good. So my content pages all Inherit from a base class. The base class has a method that
calls the GetCurrentUser from the Base class.
public class BasePage : Page
{
//.....
protected UserBO GetCurrentUserFromMasterPage()
{
this.Master
Elsa.MasterPages.MainMasterPage master = (Elsa.MasterPages.MainMasterPage )this.Master;
return master.GetCurrentUser();
}
}
So here you can see that the base page casts the MasterPage and then calls GetCurrentUser.
Just for background... The masterpages get current user logged into the system and then draws itself using the info. If the user is in the session it gets it otherwise it loads from the database. I dont want the content pages to do the same so I wanted the base page to always get the current user for the content page from the master.
However my problem is, that because there is 2 master pages and all web pages are derived from Base
page.. I need to be able to cast to the correct master.
public partial class MyMainPage : Elsa.Pages.BasePage
{
private long _userId = -1;
public partial class MyPopupPage : Elsa.Pages.BasePage
{
private long _userId = -1;
If I put in the MasterType directive I can call the method in the content page for the correct Master.
But I dont want to call it from the content as its common method so I need it in the base.
So does anyone know how to handle this. I was thinking on deriving the BasePage again for a PopupBasePage and over writing the GetCurrentUserFromMasterPage() to cast to the popup master.
Or do I pass something into the BasePage constructor to tell it what to cast to.
I want to keep the impact to all my web pages to a minium as I have a lot of web pages.
Thanks M
You can insert an extra MasterPage as the base class for your 2 current ones:
public partial class SiteMasterPage : System.Web.UI.MasterPage
{
....
// GetCurrentUser
}
public partial class MainMasterPage : SiteMasterPage
{
....
}
public partial class PopupMasterPage : SiteMasterPage
{
}
This will allow you to implement other common features and markup (include of CSS files) in one place as well.
Does it make sense for you
using Reflection:
Master.GetType().GetMethod("GetCurrentUser").Invoke();
Do this :-
public class MasterPageBase : MasterPage
{
public PageBase PageBase { get { return (PageBase)this.Page; } }
}
public class PageBase : Page
{
// Do your Extensions Here..
}
All Pages there after Inherit from PageBase.

Categories

Resources