In my prism application I want to make a single shared instance of a view. When I try to navigate the first time it works fine, but when I try to second time it's not working. If I change the PartCreationPolicy from Shared to NonShared it works but it's give me a new instance. Are there any options for another way to do this?
[Export(ViewNames.AppView)]
[PartCreationPolicy(CreationPolicy.Shared)]
public partial class AppMain : UserControl
{
public AppMain()
{
InitializeComponent();
}
}
You might want to play around with Prism's KeepAlive value for your view. This value determines whether the view should be removed from the region when you navigate away from it. You have two ways of doing this:
Using the RegionMemberLifetime attribute
[RegionMemberLifetime(KeepAlive = false)]
[Export(ViewNames.AppView)]
[PartCreationPolicy(CreationPolicy.Shared)]
public partial class AppMain : UserControl
{
public AppMain()
{
InitializeComponent();
}
}
Implementing the IRegionMemberLifetime interface
[Export(ViewNames.AppView)]
[PartCreationPolicy(CreationPolicy.Shared)]
public partial class AppMain : UserControl, IRegionMemberLifetime
{
public AppMain()
{
InitializeComponent();
}
public bool KeepAlive
{
get { return false; }
}
}
You can read some more about the KeepAlive property here.
Related
I am trying to migrate one of my macOS app to Windows UWP.
There is a requirement that I need to call the function in another class
namespace MyApp
{
public sealed partial class MainPage : Page
{
public bool isOk;
public MainPage()
{
}
public void doSomething(){
};
/*
public static void doSomething(){
isOk=false;// isOk is inaccessible
};*/
}
public sealed partial class AnotherPage : Page
{
public AnotherPage()
{
//call doSomething() in MainPage
}
}
}
it is very easy to implement this in objective-c via protocol(interface)
but in c#, the mechanism of the interface is different from the objective-c protocol.
of course, I can use the code below
MainPage mainPage=new MainPage();
mainPage.dosomthing();
but I wonder if this is valid for Page object related to the XAML file.
or there is a common usage to call the function in another class?
Your comment welcome
NOTE: This is an answer to your question but from a design perspective this is bad.
You need a reference to the instantiated MainPage. I'm sure there's one in the framework but for example just so this can be understood let's make a public static class to hold this reference.
public static class Global
{
public static Page MainPage { get; set; }
}
Now in the MainPage constructor assign itself to this property of the static Global class.
public MainPage()
{
Global.MainPage = this;
}
Now from any other page you can access it.
public AnotherPage()
{
Global.MainPage.doSomething();
}
I currently have a simple WPF application, in the MainWindow I will have a variable (In this case the variable is a class that holds data). Then I have a User Control which has the same variable.
Currently, I'm passing the variable with the ref keyword and it works perfectly fine, however, is this save/good practice? Is there a better way of linking this two variables together?
I am aware of the existence of DependencyProperty, however, I could not get it to work.
MainWindow:
public partial class MainWindow : Window
{
private TestClassWithInfo m_SelectedInfo;
public MainWindow()
{
InitializeComponent();
m_SelectedInfo = new DrawingInformation();
TestGridUC mp = new TestGridUC(ref m_SelectedInfo);
TestCanvas.Childrens.Add(mp);
}
}
TestGridUI:
public partial class TestGridUC : UserControl {
private TestClassWithInfo m_SelectedInfo;
public TestGridUC (ref TestClassWithInfo e)
{
InitializeComponent();
m_SelectedInfo = e;
}
}
TestClassWithInfo:
public class TestClassWithInfo
{
public Image imageTest;
public int intTest;
public TestClassWithInfo ()
{
m_img = null;
m_layer = 0;
}
}
I am aware of the existence of DependencyProperty, however, I could not get it to work.
A dependency property really is the way to go about it though:
public partial class TestGridUC : UserControl
{
public TestGridUC()
{
InitializeComponent();
}
public TestClassWithInfo Info
{
get { return (TestClassWithInfo)GetValue(InfoProperty); }
set { SetValue(InfoProperty, value); }
}
public static readonly DependencyProperty InfoProperty =
DependencyProperty.Register("Info", typeof(TestClassWithInfo), typeof(TestGridUC),
new PropertyMetadata(null /*or initialize to a default of new TestClassWithInfo()*/ ));
}
Now you can bind to that property from the xaml in your MainWindow:
<local:TestGridUC
Info="{Binding Info}"></local:TestGridUC>
If you need help with that part, as pr177 answered there are many tutorials on getting started with WPF with the MVVM pattern. The basics here would involve a view model object that contains a TestClassWithInfo public property that you bind to.
Have a look at the MVVM (Model-View-ViewModel) Pattern
There are many tutorials & introductions like that:
https://blogs.msdn.microsoft.com/ivo_manolov/2012/03/17/model-view-viewmodel-mvvm-applications-general-introduction/
or
https://social.technet.microsoft.com/wiki/contents/articles/32164.wpf-mvvm-step-by-step-2.aspx
I want to update textblock1 to 'there' from a class other than the main. As shown this code gives no errors, but does not work. Textblock1 is set to
FieldModifier="Public".
namespace myProgram
{
public sealed partial class MainPage : Page
{
Library stuff = new Library();
public MainPage()
{
this.InitializeComponent();
}
public void mainStuff()
{
stuff.Doit(new MainPage());
}
}
}
namespace myProgram
{
public class Library
{
public void Doit(MainPage mainPage)
{
mainPage.textblock1.Text = "there";
}
}
}
The short answer
Pass your Window as a parameter to the other class.
public class Library {
public void Doit(MainPage mainPage)
{
mainPage.textblock1.Text = "there";
}
}
EDIT According to the other answer that is posted here, you can't (by default) access controls from outside the class (as they are set to protected).
You can override the access modifier to public (refer to the other answer), but that seems to violate the idea that UI and data logic should be separated.
It does work, from a technical point of view; I just suggest not doing it because it can lead to future problems in development.
The cautionary answer
You should endeavour to keep your UI and data logic separate. In most cases where you want another class to access your window's controls; you are violating the principle of UI and data logic segregation.
In short, you don't want anyone (except MainPage) to be aware that a Mainpage has a Textblock; let alone giving them the ability to set its content directly.
In MainPage, create a public property:
public String MyDisplayValue
{
get
{
return this.textblock1.Text;
}
set
{
this.textblock1.Text = value;
}
}
In your external Library class:
public void Doit(MainPage mainPage)
{
mainPage.MyDisplayValue = "there";
}
Functionally speaking, the application works the same as in the short answer I supplied. But this one creates a better separation between UI and data logic.
This is a matter of good practice, not technical requirement.
Make you TextBlock control public like this. x:FieldModifier="public"
<TextBlock Name="TextBlockName"
x:FieldModifier="public"/>
Then expose you MainPage class
public sealed partial class MainPage : Page
{
public static MainPage mainPage { get; set; }
public MainPage()
{
this.InitializeComponent();
mainPage = this;
}
}
then in our Library class do this:
public class Library
{
private TextBlock myTb{ get; set; }
public Library()
{
myTb = MainPage.mainPage.TextBlockName;
}
public void Doit()
{
myTb.Text = "there";
}
}
I am trying to build an mvvm app using mvvmcross. When I start the app a null reference exception occurs.
this is my codebehind file which uses MvvmCross.WindowsUWP.Views.
public sealed partial class MainView : MvxWindowsPage
{
public MainView()
{
this.InitializeComponent();
MainViewModel = (MainViewModel)ViewModel;
}
public MainViewModel MainViewModel { get; set; }
public PlayersViewModel PlayersViewModel { get; set; } = Mvx.IocConstruct<PlayersViewModel>();
}
This is my app.cs file.
public class App : MvxApplication
{
public override void Initialize()
{
RegisterAppStart<MainViewModel>();
}
}
When I set an break point at MainViewModel = (MainViewModel)ViewModel; the break point is hit and I can see that the ViewModel property is null. what I am doing wrong? Thanks in advance.
ViewModel property is not yet initialized in the constructor. That's why its value is still null.
You will need to move the assignment to a different method that gets called later, e.g. OnNavigatedTo:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
MainViewModel = (MainViewModel)ViewModel;
}
Even better, instead of assigning ViewModel to your own auto implemented property, rather have the MainViewModel getter perform the cast. Then you don't even need to do the assignment:
public MainViewModel MainViewModel => (MainViewModel)ViewModel;
Unfortunatelly UWP doesn't support generic base classes in XAML, otherwise you could use MvxWindowsPage<MainViewModel> as the base page, not needing to do the cast at all.
I have several UserControls that are sharing some common properties. Example:
private List<MyObject> Sample
{
get
{
return Session["MyObject"] as List<MyObject>;
}
set
{
Session["MyObject"] = value;
}
}
I want to share this to all user controls inside my project. (Not to other projects in a solution, of course). What I'm trying to do is create a separate class and inherit from that class. Something like:
public class SampleBase : Web.UI.UserControl
{
protected List<MyObject> Sample
{
get
{
return Session["MyObject"] as List<MyObject>;
}
set
{
Session["MyObject"] = value;
}
}
}
And then my control can inherit those values by deriving from that class:
partial class myControl : SampleBase
One problem I encounter is that I cannot derive from base if control already has something inherited:
partial class myControl : SomethingELSE
Otherwise it works fine, but I'm not sure if it is a good approach and I'm looking for suggestions.
If my understanding is correct, you only want to get rid of the inheritance hierarchy of your User Controls
Another approach would be using Extension Methods
For example:
Interface to mark your USerControls
public interface IMyUserControlMark { }
Extensions
public static class MyUserClassExtensions
{
public static List<object> GetSampleData(this IMyUserControlMark myUserControl)
{
if (HttpContext.Current.Session["MyObject"] == null)
{
return Enumerable.Empty<object>().ToList();
}
return HttpContext.Current.Session["MyObject"] as List<object>;
}
public static void SetSampleData(this IMyUserControlMark myUserControl, List<object> myObject)
{
HttpContext.Current.Session["MyObject"] = myObject;
}
}
User control
public partial class Content1 : System.Web.UI.UserControl, IMyUserControlMark
{
...
}
public partial class Content2 : System.Web.UI.UserControl, IMyUserControlMark
{
....
}
Now you will be able to call your extension methods from within your UserControl or from the ASPX code behind like this:
From the UserControl
var myObject = this.GetSampleData();
this.SetSampleData(myObject);
From the ASPX code behind
var myObject = this.uc1.GetSampleData();
this.uc1.SetSampleData(myObject);
This is a classic example where you need to "favor composition over inheritance".
Instead of inheriting from the class, you hold a reference to an instance of the class. Then you provide simple pass-through code to access the methods/properties of the class.
So, for your example:
public class SomeBehavior
{
public List<MyObject> Sample
{
get { return Session["MyObject"] as List<MyObject>; }
set { Session["MyObject"] = value; }
}
}
public class MyControl : UserControl
{
private SomeBehavior _someBehavior;
public MyControl()
{
_someBehavior = new SomeBehavior();
}
public List<MyObject> Sample
{
get { return _someBehavior.Sample; }
set { _someBehavior.Sample = value; }
}
}
Another option is to allow access to the behavior class directly:
public class MyControl : UserControl
{
public SomeBehavior SomeBehavior { get; private set; }
public MyControl()
{
SomeBehavior = new SomeBehavior();
}
}
The advantage of this is that you don't have to write the pass-through code. The disadvantage is that it violates the Law of Demeter, which says that you should "only talk to your immediate friends". If you do it this way, other classes that use MyControl need to know about SomeBehavior. Following the Law Of Demeter can improve maintainability and adaptability of your code, but it comes at a cost of lots of pass-through code.
Apart from previous solutions, maybe it's time for applying some MVC/MVP pattern?
For web forms there is a great framework called WebFormsMVP: link
In the library there is a mechanism called Cross Presenter Messaging thanks to which you can share a data between your controls using the publish/subscribe pattern.
For better explanation look here and here
I suggest to give the library a chance :)
In C# you can inherit from only one class and implement multiple interfaces.
This is allowed:
partial class myControl : SampleBase
partial class myControl : SampleBase, Interface1
partial class myControl : SampleBase, Interface1, Interface2, Interface3
This is NOT allowed:
partial class myControl : SomethingELSE, SampleBase
Try making SomethingELSE inherit from SampleBase if it satisfies your design. If not, then I suggest encapsulating SampleBase as a property of each control that needs it as it also suggested #DanM.