Inheriting from Window in WPF MVVM - wpf

I'm trying to implement the following solution: https://stackoverflow.com/a/1486481/154439. In the author's solution he writes,
I created an abstract ApplicationWindowBase class that inherits from Window.
I am not sure what he means here. I tried changing my XAML from <Window ... to <ApplicationWindowBase .... No luck.
The designer-generated file for the window inherits from System.Windows.Window, but as that file is designer-generated, making changes to it does me no good. I've tried various other approaches with no success.
I am very new to both WPF and MVVM. Am I missing something obvious?

Code to go along with Kevin's comment:
Code Behind
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : ApplicationWindowBase
{
public MainWindow()
{
InitializeComponent();
}
}
XAML
<myPrefix:ApplicationWindowBase x:Class="StackOverflow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:myPrefix="clr-namespace:StackOverflow"
Title="TestWindow" Height="300" Width="300">
<Grid>
</Grid>
</myPrefix:ApplicationWindowBase>
Just make sure you use the correct namespace, mine happens to be StackOverflow.

First, xaml or not, these are all classes. Therefore, anything inheriting from another class (i.e., Window), must do so as any other class.
namespace SomeNamespace
{
public sealed class MyWindow : Window
{
public object SomeNewProperty {get;set;}
}
}
xaml is just a different type of serialization with its own set of rules. But it's still serialized XML, and as such everything must be traceable back to its original type.
How xaml does this is through a facility in XML called "namespaces". They fit well with our understanding of namespaces as C# developers, as we must map an XML namespace to a namespace in our application so that the xaml serializer can match an XML element with a CLR type.
Xaml uses a couple different ways of matching these namespaces. One looks like a URL and is defined by an assembly attribute (e.g., "xmlns="http://microsoft.com/whatevs"). This works when the assembly is external to the one you are writing in. In your case, you'll have to use the other method of identifying your namespace. This specialized XML namespace is parsed by the xaml serializer in order to identify the namespace and containing assembly of your classes. It goes by the form "clr-namespace:SomeNamespace;assembly=SomeAssembly". You can omit the assembly bit if the type is in the current assembly.
To put it all together with the above example, you would create an instance of your new window like this:
<t:MyWindow
xmlns:t="clr-namespace:SomeNamespace"
xmlns="the standard microsoft namespace here"
t:OmitOtherStuffBecauseThisIsAnExampleLol="true">

Related

Something very strange with WPF solution

This is happening in several old or new projects in my WPF based solution. I have just added a window called Dashboard, and in the generated 'Dashboard.xaml.vbfile, I entered the following code. Note it normally pastesInitializeComponentin for you when you createSub New`, but now it doesn't. So, I have:
Public Class DashBoard
Public Sub New()
InitializeComponent()
End Sub
End Class
Ans the compiler complains that:
Error 15 'InitializeComponent' is not declared. It may be inaccessible
due to its protection level.
It's as if the IDE doesn't know this is the code behind for a Window. Some kind of partial class or link is missing, yet in the vbproj file, we do still find the link:
<Compile Include="Bridge.xaml.vb">
<DependentUpon>Bridge.xaml</DependentUpon>
</Compile>
I am using PostSharp on all projects for automatic error logging, but it has never given me trouble before. It is remarkably well behaved.
ADDED:
`Dashboard.xaml' looks like:
<Window x:Class="DashBoard"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DashBoard" Height="300" Width="300">
<Grid>
</Grid>
</Window>
and `Dashboard.xaml.vb' looks like this:
Public Class DashBoard
End Class
To relate you Dashboard.xaml.vb file with the existing Dashboard.xaml file, you need to:
declare the class partial, and
make it inherit from the WPF window base class, for example:
Public Partial Class Dashboard Inherits Window
As long as your class does not inherit from Window, it's clear that it doesn't find the InitializeComponent method.
However, this does not explain why the necessary code parts are not generated automatically. How does the Dashboard.xaml file look like?

inheriting user control from a base class

I've done lots of searching and found lots of answers but for some reason it's not working for me. I have a VB app in WPF. I want some common code for user controls.
So I make a base class like this:
Public Class cU
Inherits UserControl
Public Value As Double
End Class
And a user control, the Xaml starts like this:
<UserControl x:Class="UserControl3"
So all I have to do, as far as I can see, is to change this to:
<local:cU x:Class="UserControl3"
But although no error is shown in the Xaml window, I get and error in the error list:
"local" is an undeclared prefix. Line 1. position 2.' XML is not valid
(by the way, when I did exactly this in winrt it worked fine)
I tried changing it to local to Controls and also putting cU in a namespace called local but it doesn't change.
Add your namespace in your XAML for your window tag or control tag (depends whichever you are using).
<Window x:Class="YourNamespace.YourClass"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:YourNamespace">
then you can use the <local:UserControl3 /> tag
the YourNamespace in your case would be WpfApplication1

Prism-WPF equivalent to Silverlight's: CompositionInitializer class and SatisfyImports()

i'm using Prism-MEF-WPF and Sometimes i need view model gets constructed from the XAML
of the view, so the container is not involved and can’t do the dependency injection
automatically (as there is no Export attribute used with VM).so there should be some
class in Prism-WPF like CompositionInitializer to enable me to ask the container to
do the injection.In case there is equivalent class how to use it, and in case there is
no equivalent how to construct view model from xaml of the view knowing that i use MEF.
Thanks in advance.
The problem is that you can't create an object in XAML if it doesn't have a parameterless constructor.
Using the ServiceLocator, you can achieve this. It will work as an IoC (and is set up by Prism/MEF, you just have to drop the .dll):
The xaml:
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
The code-behind:
class ViewModel : NotificationObject
{
public ViewModel()
{
var firstDependency = ServiceLocator.Current.GetInstance<FirstDependencyType>();
//... more dependencies here instead of as constructor parameters
}
//class code omitted for brievity
}
Here is the right answer which i got from Agustin Adami "http://blogs.southworks.net/aadami":
Based on my understanding the view model can be instantiated in XAML as the view’s DataContext only if a view model does not have any constructor arguments. And as far as I know creating objects defined in XAML by partnering with an Inverse of Control Container is currently not supported.
Regarding the CompositionInitializer class, as far as I know there is no equivalent class for WPF, on the other hand regarding this topic, I believe you could find the following blog post interesting:
•http://reedcopsey.com/2010/03/26/mef-compositioninitializer-for-wpf/
Also, I believe an alternative for this could be registering the CompositionContainer class like mentioned in this thread:
http://compositewpf.codeplex.com/discussions/311933
As this could let you retrieve this class for example in your view model's constructor, in order to call the SatisfyImportsOnce method to satisfy the Imports defined in the passed class:
this.compositionContainer =ServiceLocator.Current.GetInstance();
this.compositionContainer.SatisfyImportsOnce(this);
Bootstrapper class is what you are looking for. It uses UnityContainer for injecting dependencies. This link here might be of your interest too..
EDIT
If i am getting right, you want to create a ViewModel from your xaml which can be achieved like this(Here local is namespace of your ViewModel class) -
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>

XamlParseException thrown calling XamlReader.Load

I'm playing around with .net 4's System.Windows.Markup.XamlReader - just as an education exercise - and I keep bumping into the same problem: Loading xaml with XamlReader.Load throws a XamlParseException if the root object defines an x:Class, but successfully parses and loads the node if not.
Here's the code I'm trying:
using System.Windows;
using System.Xaml;
using XamlReader = System.Windows.Markup.XamlReader;
namespace WpfApplication2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// Load up UserControl1.xaml from the solution
var reader = new XamlXmlReader(#"../../UserControl1.xaml", XamlReader.GetWpfSchemaContext());
var userControl = XamlReader.Load(reader) as UserControl1;
// Do something with userControl...
}
}
}
I've tried XamlReader.Parse directly from a string holding the xaml with the same result: only works if no x:Class declaration is defined.
Removing the x:Class declaration doesn't seem like a good option, because then I lose the code-behind, specifically the call to InitalizeComponent()
The exception detail:
'Specified class name 'WpfApplication2.UserControl1' doesn't match actual root instance type 'System.Windows.Controls.UserControl'. Remove the Class directive or provide an instance via XamlObjectWriterSettings.RootObjectInstance.'
...but I don't know how (where) to set XamlObjectWriterSettings.RootObjectInstance (or indeed, if that's required?)
Any clues?
XamlReader is a parser, not a compiler, so doesn't support code-behind. If you need to associate code with your dynamically loaded XAML you can do something like wrapping it up into a control defined elsewhere that you can use an instance of in the XAML or, after reading in the XAML, connect up the code (i.e. event handlers) to elements in the resulting object.
You can't use x:Class in dynamic XAML. Instead what you can do is you can hook events after the loading XAML. please have a look at this link
Loading XAML XML through runtime?

Using Base classes in WPF

I have problem with base classes in WPF. I try to make a base class with some base elements, so that other windows can inherit these components. But all that i have, when I inherit base class is only empty window, without these elements. For better understanding i put my code here:
using XSoftArt.WPFengine;
namespace XSoftArt
{
public class WindowBase : Window
{
public WindowBase()
{
}
}
Code of the Windows, whitch inherits WindowBase:
namespace XSoftArt.WPFengine
{
public partial class NewAbility : WindowBase
{
public NewAbility()
{
base.ChildForm = this; InitializeComponent();
}
}
}
Or maybe someone can put an working example or link with implemented base classes in wpf?
Thanks
I don't think you really need to do what you are doing, but it is feasible. I think you are just forgetting to call the base class constructor.
using XSoftArt.WPFengine;
namespace XSoftArt
{
public class WindowBase : Window
{
//call base ctor
public WindowBase() : base()
{
}
}
}
You'll need to do this from your inherited classes as well:
namespace XSoftArt.WPFengine
{
public partial class NewAbility : WindowBase
{
public NewAbility() : base()
{
base.ChildForm = this; InitializeComponent();
}
}
}
And if you also have a XAML-defined view, you'll need to make sure your view is a WindowBase. To do this, change this:
<Window x:Class="MyApp.MyView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
...
>
<Grid>
</Grid>
</Window>
To this:
<local:WindowBase x:Class="MyApp.MyView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:XSoftArt;"
...
>
<Grid>
</Grid>
</local:WindowBase>
If you look at this class in Reflector you will see that the constructor calls the Window class's own "Initialize()" method, which sets a lot of things in motion. Specifically it appears to hook itself up to the Dispatcher, which is the work queue for all UI events.
In particular, you want to ensure that the InitializeComponent() method of the base class is called - this is the function that creates the controls that you defined in XAML.
Making a derived class is great if you want to inherit both controls and behaviour, but consider using Templates for a more flexible way of managing a common set of controls.
I don't think I'd ever use inheritance in WPF the way you're trying to use it.
I'll try and take a stab at answering your question. If I'm understanding you correctly, you're trying something like this:
You're creating a window that has both a XAML file and a code-behind.
You're adding "base elements" to the XAML for your window... I'm not sure what you mean by "base element", but I'm going to assume you mean you're adding UI elements to your window.
You're creating another window that "derives" from your first window in the code-behind, and the problem is that you're not seeing the UI elements on it from your "base" window.
If that is what you want to accomplish with WPF, I'd personally recommend against it, just because I'm personally not a fan of inheritance and have seen firsthand the dangers of letting inheritance get out of hand.
What you could try instead is organize your "base" UI elements into WPF UserControls. This tutorial might be able to guide you in the right direction. Good luck!

Resources