I have rewriting app into MvvM and having a problem with calling one function from viewModel. That function takes as parameter a window it should alter.
I code behind it looks like this:
this.utils = new IntroPageUtils(this);
this.Dispatcher.BeginInvoke(new Action(this.utils.InitializeWizard), null);
where
this = window which should be altered
InitializeWizard the method we are calling to make it
In code behind its quite easy but how how to achieve this in viewModel?
at this moment code behind file is clean:
public partial class IntroPage : Page
{
/// <summary>
/// Initializes a new instance of the IntroPage class.
/// </summary>
public IntroPage()
{
InitializeComponent();
}
}
and a viewModel:
class IntroPageViewModel: ObservableObject, INavigable
{
private ICommand nextButtonCommand;
private ICommand cancelButtonCommand;
private IntroPageUtils utils;
public IntroPageViewModel()
{
this.utils = new IntroPageUtils(/*What to put here? */);
this.Dispatcher.BeginInvoke(new Action(this.utils.InitializeWizard), null); // There is not such thing as dispatcher here
}
/* Rest of a viewModel */
}
I'll be grateful for any samples, guides or tutorials how to overcome this problem.
A ViewModel is set as Datacontext of a View.
For example :
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel(this);
}
}
In this example, we pass the window in parameter to the view model.
So you can store the reference to the window in the view model.
class MainViewModel : ViewModelBase
{
#region fields
private MainWindow mainWindow;
#endregion
#region properties
public MainWindow MainWindow
{
get
{
return this.mainWindow;
}
}
#endregion
public MainViewModel(MainWindow mainWindow)
{
this.mainWindow = mainWindow;
}
}
I guess it depends on the answer to a few questions. Could there be more than one instance of the IntroPageViewModel in your application? Would these be specific to the window it's view is hosted in? If so (and I assume so), why not pass in your IntroPage instance into the constructor of the view model and then use that?
The view model then has a reference to the model it represents, which is perfectly valid I think.
i.e.
View Model:
class IntroPageViewModel : ObservableObject, INavigable
{
private readonly IntroPage _model;
private readonly IntroPageUtils _introPageUtils;
public IntroPageViewModel(IntroPage model)
{
_model = model;
_introPageUtils = new IntroPageUtils(Window.GetWindow(_model));
}
}
Wherever you initialise the view model instance:
IntroPage introPage = new IntroPage();
IntroPageViewModel viewModel = new IntroPageViewModel(introPage);
Related
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 have a fairly complicated application, so I decided to organize code a bit and am having problems with references to the main class not working anymore. I already had a structure with classes, but all of them were properties of the main class and had no other class properties that would need the reference to the main class.
So my structure was like this: Main Class -> Class1, Class2, Class3 etc.
After restructuring I created a structure similar to this:
Main Class -> (Class1 -> Class12, Class13), Class2, Class3 etc.
I was passing the reference to the main class just fine to all of them before, but now that I have a deeper structure, I am getting the main class null error.
The structure relevant to this particular error is this:
MainWindow: Form -> MaxFlow (algorithm) -> LabelNodes (a part of that algorithm)
The structure is fairly simple since most of my code is completely irrelevant to the problem.
First I have the MainWindow class.
public partial class MainWindow : Form {
private MaxFlow maxFlow; // Algorithm
internal MaxFlow MaxFlow { get => maxFlow; set => maxFlow = value; }
public MainWindow() {
InitializeComponent();
maxFlow = new MaxFlow(mainWindow: this);
}
Then the Maxflow class:
class MaxFlow {
private MainWindow mainWindow;
public MaxFlow(MainWindow mainWindow) {
mainWindow = this.mainWindow;
}
and then the last class with nodes:
class LabelNodes {
private MainWindow mainWindow;
public LabelNodes(MainWindow mainWindow) {
this.mainWindow = mainWindow;
}
public AddNewNodeLabel() {
//…
// THIS PART THROWS THE ERROR (mainWindow equal to null):
Label newLabel = new Label {
Location = mainWindow.LastClickLocation,
Name = ”…”
};
//…
}
I tried setting breakpoints and found out that the reference to the MainWindow class is null already before passing it to the LabelNodes class, it gets passed as null in the MaxFlow class.
Since I had no problems before transferring the LabelNodes class from MainWindow to MaxFlow, I suspect the problem is because I am passing it two times but do not understand why this could be a problem.
Any help would be appreciated.
Your code is not correct: You should assign the this.mainWindow instead of the parameter mainWindow. It will assign the default value null in the field to the parameter. (in the Maxflow class)
class MaxFlow {
private MainWindow mainWindow;
public MaxFlow(MainWindow mainWindow) {
// mainWindow = this.mainWindow; <-----
// should be:
this.mainWindow = mainWindow;
}
Like DavidG pointed out. Better naming convension would prevent making these mistakes:
class MaxFlow
{
private MainWindow _mainWindow;
public MaxFlow(MainWindow mainWindow)
{
_mainWindow = mainWindow;
}
}
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.
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.
I try to rewrite my Application using the MVVM pattern.
I have a window to show related documents for different objects with static methods like this:
public partial class ShowRelatedDocuments : Window
{
private ShowRelatedDocuments()
{
InitializeComponent();
}
public static void ShowRelatedDocument(A objA)
{
ShowRelatedDocuments srd = new ShowRelatedDocuments();
srd.HandleA(objA);
srd.ShowDialog();
}
public static void ShowRelatedDocument(B objB)
{
ShowRelatedDocuments srd = new ShowRelatedDocuments();
srd.HandleB(objB);
srd.ShowDialog();
}}
Is there a way to keep these methods static like this?
ShowRelatedDocumentsVM.ShowRelatedDocument(A objA);
ShowRelatedDocumentsVM.ShowRelatedDocument(B objB);
I didn't find anything about ViewModels and static methods. Can a VM create a instance of itself and show his View (here a window)?
Or is the better way to pass the objects as parameter to the constructor of the VM like this?
public ShowRelatedDocumentsVM(A objA)
{
HandleA(obj A)
ShowRelatedDocuments srd = new ShowRelatedDocuments();
srd.DataContext = this;
srd.ShowDialog();
}
public ShowRelatedDocumentsVM(B objB)
{
HandleB(objB);
ShowRelatedDocuments srd = new ShowRelatedDocuments();
srd.DataContext = this;
srd.ShowDialog();
}
Or are both ways wrong, cause i breach the MVVM pattern due creating the view in the viewmodel?
Thx in advance.
How to display dialogs is one of the areas of MVVM that is not immediately clear, and there are a number of ways the behaviour can be achieved.
I would suggest using either a mediator (as described here) or by injecting a dependency on the view model that controls dialogs:
interface IDialogService
{
void ShowRelatedDocumentsA(A a);
}
...
class MyViewModel
{
private IDialogService _dialogService
public MyViewModel(IDialogService dialogService) { _dialogService = dialogService; }
public void DoSomething()
{
_dialogService.ShowDialog(...);
}
}
Either of these can will permit you to control the creation of the view outside of the view model, and will remove any explicit references from VM -> V.