How do I make a field global to my site? - asp.net

Okay, this is a bit abstract, but here goes:
I'm creating a website and I want to have a field, "foo", that I can access from any page on the site. I figured the best way to do this would be to create a subclass of Page called "bar", add the protected field "foo" to it, and then have all my webpages inheret from "bar". Ta-da. Every page now has foo.
But now I add controls to my pages, and I want them to have access to "foo".
Well, now foo can't be protected, so it's public. Fine. But how do the controls know about "foo"? I can access foo by doing something like this in my control:
Foo foo = ((Bar)Page).foo;
This works, but strikes me as a bit ugly. I'd really like to just be able to use foo. I figure, hey, maybe I can do the same trick with my controls that I did for page. I create a new class, "blargh" that inherits from UserControl, and grab foo in there the ugly way. Then I have my controls inherit from blargh. Yay!
Except it doesn't work. When I start up the project it complains about the line trying to access ((Bar)Page).foo, because Page is null. Why? How could Page be null? When I look at the call stack I get no help.
Is there an easy, well understood way to do this? Am I barking up the wrong tree?

Another easy way to get started with this, before you decide which objects will need access and which won't, is to simply make a public static class to hold this and other global objects. Something like:
public static class Globals
{
public static Foo foo = new Foo();
}

If you need every user to have their own instance you can store it in the session.
Session["foo"]=data;
Then on your other pages you can use:
Control ctl = (Control) Session["foo"];
Keep in mind you will have to cast Session["foo"] to whatever type you want to work with. there is also a similar Application[] space which can be used if you only need one instance for every user of the website.

What do you need access to? If its data, why not put the value of foo in the Session? Then it can be accessed from anywhere.

One option to look at is to extend the page class using extension methods
Then Page will have Foo available whenever there is an instance of Page. Depending on what Foo is doing you will probably still need to store the data in session.
As for why Page is not available in your control. The Page property is only populated once the control has been added to the page. If your control does not sit directly on the page, then it is when it's anscetor that does sit on the page is added to the page.

You have to determine if this [foo] is going to be the same for all users or if it is specific to a single user. If it is the same for all, a Static class with static variables will solve this for you.
public static class FooClass {
public FooClass() {
}
public static string FooName = "TheFoo";
}
If you are looking at something that is going to be specific per user, I would recommend using the Session to store this. You could put your FooClass into the session as well, its really up to you as to what you're putting there.
FooClass myFoo = Session["CurrentFoo"] as FooClass;

Is foo the same value shared globally, or does it vary for each page?
I see two possibilities you might like:
Put it into the Application object of ASP.Net (I don't remember exactly where it hangs in asp.net, but with that name you can find doc on it). This would be for a global value that does not vary.
Make it an extension method on Control. Page ultimately inherits from Control, so it will be available. Like this:
public static class ControlExtensions
{
public static Foo foo(this Control self)
{
return foo;
}
}
Now UserControls and Pages should be able to get to it.

Related

Storing a view in Xamarin.Forms MvvmCross

I have an app with four main pages, switched through a tab bar (no "back" button).
One page has a lot of content (ScrollView) and takes quite a few seconds until it's rendered. I handle that by showing a "loading" overlay while the work is done. But for that specific page I'd like to keep the view alive, so that when the user switches to another page and comes back later, the page is ready without loading everything again.
I'm not sure how to do that in MvvmCross, though.
I did read the documentation and from what I understood the View Presenter would be the right way to do it, since the docs say:
"Another kind of presentation changes your app can request through
hints includes clearing / modifying the BackStack, changing a root
while maintaining the existent views, … possibilities are really
endless. Once again your app is king here!"
I guess I would need to create a custom MvxPresentationHint for that, but I don't quite get it :(
How or rather where would I access and store/load the View?
I'm generally still quite unfamiliar with MvvmCross (how it works under the hood) and especially customization of Mvx classes, even though I've been using it for a while.
Any explanation and preferably code examples beyond what's written in the documentation would be extremely appreciated!
It isn't meaningful to attempt to "store" a view in MVVM. The XF view is a representation of what will be created with native (e.g. "Android" or "iOS") widgets. Creating and measuring/laying out those native widgets is what is slow. MVVM View Presenter won't speed up that logic.
Instead of "store", you need "keep alive":
For a ContentPage called MyPage, when you create it, store it in a static variable. Then re-use that variable. If you never need more than one of these, you can store it in the class itself.
Modify the "code behind", MyPage.xaml.cs:
public partial class MyPage : ContentPage
{
// Singleton Pattern.
private static MyPage _it;
public static MyPage It {
get {
if (_it == null)
_it = new MyPage();
return _it;
}
}
// "private", because calling this directly defeats the purpose. Instead, use `MyPage.It`.
private MyPage()
{
InitializeComponent();
}
}
To create it, whereever you would put:
new MyPage()
instead put this:
MyPage.It
For instance, you might do PushAsync(MyPage.It);
This will always return the SAME INSTANCE of MyPage. So once it has been created, it keeps its state.
IMPORTANT: Note that the constructor is only called ONCE. Any code that needs to be done each time the page appears, put in override .. OnAppearing() method.
LIMITATION: Views "expect" to be part of the visual hierarchy when they are manipulated. If you attempt to alter the page or its view model while it is not on the screen, you may encounter problems. Those are beyond the scope of this answer - create a new StackOverflow question with the details of any problem you encounter.

How do I run code at client start (Not at page open) in Blazor

I need to run some code to get a user's username and department when they first connect to my Blazor Server Side application. I could just do this using OnInitialized() but that appears to only work on the one page in which it was placed. Users will likely be sent separate links to different pages though and I don't want to have to place this code on every page. I discovered that I can place code in my main layout and it will run no matter what page I start on but it runs on every page change and it doesn't allow me to run things asynchronously so that's not ideal. I'm looking for something like a Global.asax but in Blazor if that makes sense.
Edit: Turns out I can run things asynchronously in my layout! I just needed to create a code block like any other razor page. Makes sense. Though It's still weird that we have to put this type of code in the layout. It just doesn't feel right.
This is what I do:
Create a state object (class) that can be injected where needed. This is somewhat like session, but can also have global events. See here.
Add it to IoC in Startup.cs. Background info here
services.AddScoped<MyState>();
Initialize it in MainLayout.razor or elsewhere:
if (MyState.User == null)
{
MyState.User = authService.User;
}
Instantiate in pages/components as needed:
[Inject]
public MyState myState { get; set; }
...
myObj.CreatedBy = myState.User.UserName;

adobe flex static function reference control

Is it possible to reference a control in an application from a static function?
What I have is a Viewstack containing VBoxes stored in separate controls. Ex:
<mx:ViewStack id="content" width="100%" height="100%" resizeToContent="true">
<controls:Login/>
<controls:Dash/>
<controls:Input/>
<controls:Review/>
<controls:Search/>
</mx:ViewStack>
Once I get logged in on my login control, I would like to change the selected index of my ViewStack. From my outside controls, I cannot reference my ViewStack by name. I can reference a public static function from an outside control however I cannot refer to the ViewStack from within that function. Any help is greatly appreciated.
JH
Normally you can have a singleton class where you can save the
instance of the main application and if you view stack is resides
inside your main application then you can do some thing like this
public static function changeIndex(index:int):void
{
FlexGlobals.topLevelApplication.content.selectedIndex = index;
//urappinstance.content.selectedIndex = index;
}
You could reach it starting from FlexGlobals.topLevelApplication (if it is visible from there). Although, the design of such a thing may be questionable.
Is it possible to reference a control in an application from a static
function?
Generally no. A static function (or property) exists on the class itself. Whereas MXML Children--such as in a view stack--exist on a specific instance of the class. A class level function will know nothing about any specific instances of the class and will not be able to access properties on a specific instance.
However, you can pass an instance of a class into a static function and access the properties that way. something like this:
public static function doStuff(myViewStack:ViewStack):void{
trace(myViewStack.id)
// do other stuff
}
And call it like this:
MyClass.doStuff(content)

What's the base class of a Razor View in ASP.NET MVC3

I'm trying to have all my views inherit from a custom class so that I can add certain behaviour and values to all pages, but I'm having some issues. I tried subclassing System.Web.Mvc.WebViewPage but I'm forced to implement an Execute procedure that I don't know what it should do. Also, if I try to access the Context variable, I get a null reference (really weird). This leads me to think that I may have the wrong base class....
Any thoughts?
Diego, System.Web.Mvc.WebViewPage is the right base type (and you should have another class inheriting from System.Web.Mvc.WebViewPage<TModel> if you want strongly-typed views). You should mark your own class as abstract so that you are not forced to implement the Execute method.
Update: To configure all your views to use your custom base class, look into the ~\Views\Web.config file. Inside of it there's a Razor-specific section where you can use the pageBaseType attribute to configure your custom type.
As far as the Context property is concerned, it should be fully initialized once the view is executing. However, it might not be available if you try to access it too early (for example, from your classes constructor). When are you trying to access it?
The Execute method is something that is provided by the Razor compiler when your view is compiled. For example, given the following view file
Hello #Name!
The Razor compiler will behind the scenes generate the following class (this is a simplification, so the details might be off, but it should convey the point)
public class _Some_Generated_Class_Name_ : System.Web.Mvc.WebViewPage {
public void Execute() {
Write("Hello ");
Write(Name);
Write("!");
}
}
Then the framework calls the Execute method on your view class and your view gets executed.

Cannot access custom properties on nested user control

Ok, please understand the architecture here first.
OurMasterPage.aspx has user control Header.ascx
Header.ascx has a user control in it called LandingPageTopNav
LandingPageTopNav.ascx has a public property named "LandingPage" that is there to be able to set by the user using this control.
And I have a Third.aspx page in which I need to set the LandingPageTopNav property to a LandingPage object
The problem is that I can't get this to work in my ThirdPage.aspx.cs:
Master.LandingPageTopNav.LandingPage = this.landingPage;
Master.LandingPageTopNav.Visible = true;
And that is, I can't get the first line to work where I'm trying to reference the LandingPage property. The second line is fine. My Third.aspx definitely can reference my master page objects otherwise from code-behind.
I'd venture to guess that the LandingPageTopNav property of OurMasterPage doesn't return a value typed as LandingPageTopNav. It probably returns the correct control typed as something more generic (e.g. Control); which is why setting the Visible property works but not the LandingPage property.

Resources