How to cast SourcePageType as Page? - c#

Well I'm building a WinRT app currently and I am facing this issue.
What I am trying to achieve is that I need to read or modify the properties on previous page that I am navigated from.
So let's say that I have two pages: MainPage and WatchPage.
I am navigating to WatchPage from MainPage and inside the WatchPage's OnNavigatedTo event I need to access a property inside MainPage without using navigation parameters...
How can I achieve this?
protected override void OnNavigatedTo(NavigationEventArgs e){
Type LastPage = rootFrame.BackStack.Last().SourcePageType;
if(LastPage == typeof(MainPage){
// here, for example, say that MainPage has a property called isLoadSuccess
// I need to set that property to false
// or call a method from MainPage
// => this is not working MainPage MP = LastPage as MainPage;
// I know that it should not work anyway, but, how can I achieve this?
}
}

What you are attempting to do cannot be accomplished using the existing framework. That is to say, a reference to the instance of your previous page does not exist in the BackStack. The only thing that exists is, honestly the recipe to re-create the instance. That is to say, the BackStack contains the type and the parameter. With those two elements, you should be able to re-instantiate the class when the user navigates back to it in the Frame. These ingredients, by the way, include the type and the serializable parameter - only with a serializable parameter can the app save the BackStack to NavigationState and reliably restore it should your application be suspended/terminated.
That's the story, now to your problem. I see several possible solutions, to be honest, and I think any of them are acceptable.
The first caveat is that you MUST use NavigationCacheMode = Enabled. Without this, your page (including the previous page) will be re-created with every navigation, including Back. This is an important behavior of UWP because it assumes your page is removed from memory to save the overall footprint. Setting NavigationCacheMode will override that.
Create a static reference
This is easy enough right? Something like this:
public readonly static MainPage Instance;
public MainPage() {
Instance = this;
}
Beware of this, because it requires your views to have a reference to each other. This is a pretty minimal risk, IMHO.
Pass a reference
This is easiest to accomplish with Navigate(parameter) like this.
// MainPage
public void GoAway() {
this.Frame.Navigate(typeof(SecondPage), this);
}
// SecondPage
MainPage MainPage;
public void OnNavigatedTo(object parameter) {
MainPage = parameter as MainPage;
}
Beware of this because it requires you to pass something that cannot be serialized. Sometimes, though, this is acceptable.
Any of those make sense?
Best of luck.

I'd recommend to create a static class with static properties and methods.. I don't think what you try to achieve is a good practice.. instead, here's my example:
public static class Shared
{
public static string property = "something..";
public static async Task<bool> Method()
{
await Task.Delay(400);
return false;
}
}
Then, you can call the method, get or set the property from any where:
bool result = await Shared.Method();

Related

Using ref in (whole) partial class

I got some confusion about "the right way" to use a reference in a partial class.
Basically i wrote a WPF program which has different Menus. Every Menu got the same Viewmodel and some data-related object class. In my case i call the Object "DataModel" which i want to use as reference in every menu. I just came across a problem when ich switched my DataModel from a static object to the desired instance for every Menu as input ref. (i still want to use one and the same DataModel for every menu though...)
But in the "lower" methods it says that _dm is simply not defined.
Code shortly summarized as:
public partial class FormatWPF : UserControl
{
public FormatWPF(DataModel _dm)
{
InitializeComponent();
if (this.DataContext == null)
{
this.DataContext = _dm.g1.MVM;
}
}
// here come several Methods with which i want to calculate stuff and "manipulate" the DataModel
private void Steinformat_berechnen()
{
_dm.g1.FormatNr = _dm.g1.FormatAnzahl + 1;
}
//....
}
Shortly said i want to use the _dm which is given as input ref in the Constructor of the class object for every other method in the whole partial class as well (is it really necessary to define this ref for every method ?) Using the DataModel as static seemed so easy for me.... but basically it is "wrong" ?
Thanks in advance for some help and tips about doing it the right way.
Maybe i was a little bit unclear. The thing is i want to use just one DataModel for all the menu and my whole project. Nevertheless i dont want to make it as static ( there occured some other confusion in later parts of my code... ) So basically i have to give in the DataModel as ref for all the Menus...
Concerning your answer: I know the possibility to define another
private Datamodel _dm;
in the namespace..
But im not quite sure about:
1)won't i got here some additional "memory" usage by defining another DataModel for every menu ? becuase it is somehow "big"
2)when i now calculate data in the _dm, will it change for the "complete" program ? like in the former static Model ?
I hope to make the DataModel static then is not the "right answer" to my problem because i just wanted to get away from this somehow ... hm
Best regards
Knally
Yes, static is very wrong if the DataModel is a per-instance thing (static means all the instances would be using the same value); but it can still be an instance field:
private DataModel _dm;
public FormatWPF(DataModel dataModel)
{
_dm = dataModel;
// the rest of your constructor code here
}
Now you can use _dm in all of your other instance methods, and everything should be fine. If you only ever need _dm.g1, you could perhaps store that value as the field, instead of the model itself.

How to fix "inaccessible due to its protection level" error in winform?

I have a Form class
partial class ProgressMainForm : Form
{
public ProgressMainForm()
{
InitializeComponent();
}
}
And then a class that uses that class and contains all functionality for the user
public class ProgressForm
{
public ProgressMainForm myProgressForm;
public ProgressForm(string title)
{
myProgressForm = new ProgressMainForm();
myProgressForm.Text = title;
}
public void SetProgressBar(int min, int max)
{
....
}
I then use this ProgressForm class in my project like this
progresswindow = new ProgressForm("Replacing All Strings");
This way progresswindow only contains members that are related to the functionality of the ProgressForm and all those Form members are hidden from the user.
But sometimes I need to access those Form members, for example when I need Invoke method.
Is there a way to make myProgressForm in ProgressForm accessible to users without making ProgressMainForm public?
Or is this approach wrong?
In my opinion you should not work with the form directly. If I read your setup correctly, you want to show progress indicator while some job is being done. ProgressForm should expose methods to set the counters and increment them; as you run it on another thread, form manipulation should be done from inside the methods of ProgressForm. Your Invokes belong there, wrapped in suitable methods. If you want to change some visual properties of ProgressMainForm relay those properties to ProgressForm.
To resume, calling code should have no clue what ProgressForm does other than setting progress boundaries, starting, setting current percentage and stopping. This way, if you are asked to port the application to another UI system the amount of code you will need to change will be drastically reduced.
Is there a way to make myProgressForm in ProgressForm accessible to users without making ProgressMainForm public?
Yes, you can create some public properties on ProgressForm that expose specific properties of ProgressMainForm.
private ProgressMainForm myProgressForm;
public int SomeProperty
{
get { return myProgressForm.IntProp; }
set { myProgressForm.IntProp = value; }
}
For readonly properties, omit the set, and for any types that are reference types, you may want to return a clone or copy (to ensure the client can't change it).
Wrap or Expose the Methods you need. But somehow i don't like the approach, restricting the access is not a bad idea but should not be the whole purpose of this kind of abstraction. Try to make the acess easier, not restrictive.
You can declare the methods as internal , This will allow you to call the methods from within the assembly.

Writing in a textbox in a form from another class

I need to write the result of my query in a textbox in the main form, from another class. What is the best and easy way to achieve this?
Your external class should not know anything about a textbox. It may know about your form in order to send the result there, but the elements are belong to the form and should not be exposed (it is what is called encapsulation).
I suggest you to have a meaningful method on your form, something like ShowListOfUsers(users), or whatever you do, call it appropriately so it can be understood externally.
Then in this method you put the result into the controls (textbox) as you want it.
I also suggest you to have an interface for the form which will contain such behavioral methods and have your window implemented this interface, something like:
public interface IOrderView
{
void ShowOrderDiscount(result);
}
so your external class will know only about the interface, not about the window, the textbox, etc.
Now your query component is trivial:
public class SomeOperation
{
private readonly IOrderView _view;
public SomeOperation(IOrderView view)
{
_view = view;
}
public void DoSomething(parameters)
{
var result = GetMyComplicatedResult();
_view.ShowResult(result);
}
}
The code above is not ideal (as I don't know what is your scenario), but the idea is there.
Good Luck.
Use a public property (or a getter) in your class to retrieve the output of the query.

Global Variables vs. ASP.NET Session State

This is probably going to sound rather naive, but I'm developing a web application that spans multiple pages. All of these pages instantiate the same class object w/ methods that accesses a CMS using their API. Currently, when a user starts creating content, I'm storing variables like a folder ID where the content is located in a Session variable.
My question is this: Can I instantiate a single instance of a class that can be used across all pages without having to do it on every page? If so, would each person accessing that page be given their own version of the class? I assume that using static variables and methods isn't the way to go since they are shared in memory. And also, where/how is something declared if it is going to be used globally in a Web Application in a .net C# application?
I recommend making a base class which inherits from System.Page. Then have your page code behind inherit from that.
Then, inside the base class, create a property that is a reference to your object. Like this, for example:
public class BasePage : System.Web.UI.Page
{
public Foo CurrentFoo
{
get
{
return (Foo)Session["FooSessionObject"];
}
set
{
if(Session["FooSessionObject"] == null)
{
// instantiate a new one
Session["FooSessionObject"] = new Foo();
}
Session["FooSessionObject"] = value;
}
}
}
Then, from anywhere in any page, just do a CurrentFoo. and you will have access to any of the properties.
This makes for nice and clean code behind.
You should use Session state if you want to store information that is specific only to the current user.
For example in one page of the application you could store some value into the session:
SomeType someValue = ...
Session["someKey"] = someValue;
and then later on other page retrieve it from the session:
SomeType someValue = (SomeType)Session["someKey"];
The pattern you are looking for is quite easy. There are a couple of ways to accomplish it.
Create an object and store it in session
Create a multi-part form and leave the items in viewstate
Each has its benefits.
Bad thing about doing this and using global over sessions for website is the simple fact that global variables could be accessed by any user accessing the regardless of session. For example take the code below.
public class globals
{
static string _test = "MyTest";
public static string test
{
get
{
return _test;
}
set
{
_test = value;
}
}
After I created the global class I added a label to my default from and assigned the global variable text to the label.
protected void Page_Load(object sender, EventArgs e)
{
globals.test = "Some Data";
}
now you will see this on every form of you page however the down side to this is anyone else that accesses your page will also be able to see this data. If its data that needs to be shared across multiple sessions you could do this. If its data that just needs to be shared by the current user over multiple classes you need to use session variables.

Accessing derived class from base class object issue

I have a kind of weird situation ...
I have a User Control in WPF witch in turn has some other User Controls attached to it, then I have a huge C# code file with a big algorithm which needs access to the User Control UI Elements and methods, this hole process works with a Timer which sends data to the C# code file algorithm from the User Control and it needs to return and update the UI elements from the control and also to access it's methods...
Now the thing is I don't want to put this huge algorithm in the codebehind file of my control, instead I would like to access the control's UI elements and declared methods from that code file ...
What I tried so far is to actually derive the code file's class from the User Control I use, this works fine and dandy but to access the derived class I need to create a new object of it and the UI that I get shown does not get updated since it also creates a new base class object I believe ...
so I have something like:
public partial class usrctrlSimulator : UserControl
{
public usrctrlSimulator()
{
this.InitializeComponent();
}
public void StartSimulator()
{
Algorithm = new csAlgorithm();
Algorithm.InitializeSimulator();
timer1.Start();
}
}
public class csAlgorithm : usrctrlSimulator
{
public csAlgorithm()
{
}
public void InitializeSimulator()
{
txtblkSimulatorStatus.Text = "Started"; // this element would be from the user control
}
}
So my question is : how do I call the derived class without instantiating a new object of it, since that will cause a new user control object to be created and the displayed UI will not be updated ... or if I don't derive the Algorithm class, what possibility do I have to access the user control elements and methods ?
If you want to stick with one instance of the control and still have access to the functionality in the derived class then you need to use the derived class as the control. So instead of an instance of usrctrlSimulator, you'd use csAlgorithm everywhere.
However, I'm not sure whether this design is the best approach in your scenario. The algorithm is not really a user control so maybe deriving from usrctrlSimulator is not the ideal option. For example: UserControl has a method called ApplyTemplate(). What would be the meaning of this in csAlgorithm? You can also look at it from a different angle: Would it be reasonable to use csAlgorithm wherever you could use UserControl, e.g. when invoking UserControl.AddLogicalChild(csAlgorithm)?
A different option would be to instantiate the algorithm as a member variable in usrctrlSimulator (composite). In that case you could still use it inside the usrctrlSimulator but you would have a clear separation of two concepts: A UserControl on one hand, and the implementation of an algorithm on the other hand. In addition you could then change either one of them with only limited impact on the other.
In that case your code would look as follows:
public partial class usrctrlSimulator : UserControl
{
public usrctrlSimulator()
{
this.InitializeComponent();
}
public void StartSimulator()
{
_algorithm= new csAlgorithm();
_algorithm.InitializeSimulator();
timer1.Start();
}
private csAlgorithm _algorithm;
}
public class csAlgorithm // not a UserControl anymore
{
public csAlgorithm()
{
}
public void InitializeSimulator()
{
txtblkSimulatorStatus.Text = "Started"; // this element would be from the user control
}
}

Categories

Resources