I am trying to us the demo code from wpf chrometabs and in the other application I just added a button that calls the constructor of the demo:
private void FrontendDebug_Click(object sender, RoutedEventArgs e)
{
Demo.MainWindow mainWindow = new Demo.MainWindow();
mainWindow.Show();
}
The problem is that it throws an exception at the InitalizeComponent:
I read somewhere that in MVVM, the DataContext should be set before calling InitializeComponent() but I don't know if that is the problem here or how to do it if it is.
The error that you get points out, that you use a StaticResource markup extension to reference a resource with key Locator that is not found in this line:
DataContext="{Binding Source={StaticResource Locator},Path=ViewModelMainWindow}"
The locator is defined in the application resources, so it is accessible in the whole application. Either you accidentially removed it or there is a typo in App.xaml. Make sure that it looks like this.
<Application x:Class="Demo.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" StartupUri="MainWindow.xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" d1p1:Ignorable="d" xmlns:d1p1="http://schemas.openxmlformats.org/markup-compatibility/2006">
<Application.Resources>
<vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" xmlns:vm="clr-namespace:Demo.ViewModel" />
</Application.Resources>
</Application>
I am trying to us the demo code from wpf chrometabs and in the other application I just added a button that calls the constructor of the demo:
If you have another application that uses the demo project as library, the call below will only create an instance of the MainWindow. It will not bootstrap the application in the demo project.
Demo.MainWindow mainWindow = new Demo.MainWindow();
Consequently, the App object from the demo project is never created and its resources are not available. Even if it would be bootstrapped, the resources defined in App.xaml only apply to this application, nothing else.
Therefore, the mainWindow instance will try to find the resource in your application, not in the demo application. Since it is not defined there, you will get an exception. You could add the view model locator to your application's App.xaml resources, but keep in mind that is applies to all resources defined on the application level.
Related
During development of my UWP app I have noticed and intersting oddity which I have hard time explaining.
I user MvvmLight and I decided to add the ViewModelLocator resource instance in a separate ResourceDictionary Core.xaml which will be referenced from MergedDictionaries in App.xaml.
Following is the content of App.xaml:
<Application ...>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Core.xaml" />
<ResourceDictionary Source="Resources/Converters.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Contents of Core.xaml:
<ResourceDictionary ...>
<viewModel:ViewModelLocator x:Key="Locator" />
</ResourceDictionary>
Now I supposed the resources in Core.xaml are initialized during the InitializeComponent method call in App.xaml.cs, but when I tried to use the ServiceLocator class (which is set in the constructor of ViewModelLocator in MvvmLight) - like this - ServiceLocator.Current.GetInstance<INavigationService>().Navigate<MainViewModel>(); - I get an exception saying:
An exception of type 'System.InvalidOperationException' occurred in
Microsoft.Practices.ServiceLocation.dll but was not handled in user code
Additional information: ServiceLocationProvider must be set.
Indeed, if I put an breakpoint in the constructor of ViewModelLocator, it is not called before the Window is activated. More interestingly still - if I manually reference the Locator resource key (for example putting Debug.WriteLine(Resources["Locator"]); above the call of ServiceLocator), everything works fine. The same goes if I move the ViewModelLocator resource directly to App.xaml - then it is instantiated during IntializeComponent.
Is there a lazy instantiation of merged resource dictionaries in UWP apps? Or why does it behave this way?
A ResourceDictionary in UWP doesn't have any code behind (no InitializeComponent). Therefore, any class references defined in a ResourceDictionary won't be initialized directly.
Neither does the App.InitializeComponent do this for you. Resource dictionaries in UWP just don't provide this functionallity - don't ask me why.
You can easily try this by trying to initialize a DataTemplate in a ResourceDictionary.
This should - sadly - neither work.
However, using the Resources["Locator"] access in code behind triggers the constructor of the class and you're fine.
This ain't be a solution, but a explanation of your problem.
I hope it helps you.
Let's start from the beggining. I have an app in wpf which uses my custom window style. I'm defining this custom style in app.xaml like below:
<Application x:Class="GeoLocations.Test.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ThemedWindowStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Nowadays there came a requirement that i need to build this application as dll and later on call it from Windows.Forms application. Obviously the app.xaml code is not being fired since this is not start up application anymore. Is there any way to load it ?
I tried to manually register this Dictionary in code behind but with no success. I also tried to change Build Action from "Page" to "Content" and "Do not copy" to "Copy if newer" but it is giving me different exception:
'Failed to create a 'Type' from the text 'local:ThemedWindow" with inner exception "{"Type reference cannot find type named '{clr-namespace:GeoLocations.Test}ThemedWindow'."}
(this exception is beeing fired inside ResourceDictionary so it's loaded but why it can't find the type ?).
ThemedWindow is a type which inherits from Window and later on all my windows inherits from ThemedWindow instead of Window
I have no idea how to solve this issue. Anyone got some knowledge to help ?
Ok, so i resolved this be adding my ResourceDictionary in code behind in my ThemedWindow Constructor. Like below:
var rd = new ResourceDictionary();
rd.Source = new Uri("pack://application:,,,/GeoLocations Screens;component/ThemedWindowStyle.xaml");
Resources.MergedDictionaries.Add(rd);
I have a solution with three projects. One is for Testing using CodedUI, the other is a WPF Viewer application that shows the data from the tests, and the third is a project of Models.
If I set the WPF project to be the start up project in the solution and run it in debug mode the theme shows up just fine.
If I attempt to start the WPF MainWindow from the Test Project, everything shows the same, without the Theme. When the test project wants to show the data it does so by firing an event to this method in the WPF project.
public static class Start
{
public static EventHandler<List<SomeData>> NewData = ShowData;
private static void ShowData(object sender, List<SomeData> e)
{
MainWindow.NewData(sender, e);
var mw = new MainWindow();
mw.ShowDialog();
}
}
I have single stepped through this code, the data arriving and the mainwindow coming up just fine. But why wouldn't the code above include the theme?
There are no loading errors in output window.
The App.XAML is where the reference to the theme is located. But it is also where the StartupURI is located which is MainWindow.XAML. Do I need to somehow start App.XAML to get the theme?
Please advise...
How to start a WPF application and ensure the Theme works! (given the situation mentioned above)
var app = new App();
app.InitializeComponent();
app.Run();
Where App is your WPF application found here ==> App.xaml/App.cs and App.gs.i.cs.
The InitializeComponent call was the key. In the gs file this line is does the magic.
System.Windows.Application.LoadComponent(this, resourceLocater);
Notice the "this" keyword. It is a reference to the App class itself which in the XAML have these "references/attributes/resources"
<Application x:Class="AuomatedTest.Viewers.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/ExpressionDark.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
The Theme itself was located in the project with these build attributes:
The bin directory had no folder named "Themes" in it; rather, it was the obj folder that contained the Theme; however, it was the "compiled" version of the file denoted by the .baml extension.
This means that the Page attribute of the XAML file compiles it. But what it doesn't tell us is how a reference like this is adequate.
<ResourceDictionary Source="Themes/ExpressionDark.xaml">
Today we know that without the Application.LoadComponent being called from the place we referred to the Theme (App.Xaml)that no Theme will be displayed. LoadComponent then knows how to interpret .BAML files and treat them as if they actually existed in the location that was referenced.
I'm new to WPF. Here is xaml defining a window defined inside a DLL:
<Window x:Class="MyNamespace.MyClass"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d1p1="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
d1p1:Ignorable="d"
xmlns:attachedProperties="clr-namespace:MyNamespace.AttachedProperties"
xmlns:viewModels="clr-namespace:MyNamespace.ViewModels"
DataContext="{Binding Source={StaticResource VmLocator}}"
Title="{Binding MyVm.MyTitle, Mode=OneTime}" Height="300" Width="460">
<Window.Resources>
<viewModels:ViewModelLocatorTestSteps x:Key="VmLocator" d:IsDataSource="True" />
</Window.Resources>
When the client code constructs this window object, this exception is thrown:
Cannot find resource named 'VmLocator'
How do I define the resource earlier so that it exists when it is needed? I'd also prefer the solution enable Intellisense to work. This is my first attempt at a window defined inside a DLL.
Using Visual Studio 2013.
If you want the Window to create its own DataContext, you can just stick that in the constructor in the code-behind, and avoid the necessity of making your VmLocator a resource. The resources of a WPF control (including a Window) are available to children of that control.
just:
public MyNamespace()
{
InitializeComponents();
this.DataContext = new VmLocator();
}
If you really want to make your DataContext a resource, you could create an application-level resource and reference that.
Also - 'MyNamespace' is a very confusing name for a class :)
I have WPF project and some resources defined in App.xaml that are used in other files. When I try to move App.xaml to subdirectory designer is no longer able to find those resources. My project still compiles since I use 'Startup' event instead of 'StartupUri'. How to tell the designer where to search for resources? How it knows where they are when App.xaml is in root of project?
Update:
Project files:
App.xaml:
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="startup">
<Application.Resources>
<SolidColorBrush Color="LightGray" x:Key="brush" />
</Application.Resources>
</Application>
App.xaml.cs
namespace WpfApplication1
{
public partial class App : System.Windows.Application
{
private void startup(object sender, System.Windows.StartupEventArgs e)
{
new MainWindow().Show();
}
}
}
MainWindow.xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300" Background="{StaticResource brush}" />
MainWindow.xaml.cs
namespace WpfApplication1
{
public partial class MainWindow : System.Windows.Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
Update 2:
Uploaded zipped solution to http://zalil.ru/30771604 (download will start automatically)
Mirror: http://www.speedyshare.com/files/27697250/WpfApplication1.zip
1. Move you App.xaml to your desired location
2. Refactor you App.xaml.cs namespace to accommodate the new change:
3. Rebuild your solution.
[4]. Go to your project properies and set the Startup object to your App.xaml file at the new location.
[5]. Run your application and it should work successfully :)
I can't duplicate the problem on my end. Here's what I tried:
I created a application with a style in the resources of App.xaml. I moved App.xaml to a subdirectory. I have another window that uses the style defined in the resources of App.xaml (he resides in a different directory) and it was able to resolve it just fine. I added ..\ to the beginning of my original StartupUri.
I did some searching, what version of Visual Studio are you using? Apparently there may be an bug related to your problem in VS2008:
http://bengribaudo.com/blog/2010/08/19/106/bug-single-application-resources-entry-ignored
He says a workaround for this bug is to set the x:Name attribute on Application. Hope that helps!
EDIT: I also tried handling the Startup event instead of using the StartupUri and it still worked fine.
public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
new MainWindow().Show();
}
}
EDIT PART 2:
Okay, I enclosed the SolidColorBrush inside a ResourceDictionary as such:
<ResourceDictionary>
<SolidColorBrush Color="LightGray" x:Key="brush" />
</ResourceDictionary>
And the window picks up the brush. The designer doesn't like it, but when I change from StaticResource to DynamicResource it stops complaining.
EDIT 3:
I just thought of something. Do you have VS2010 SP1 installed? It fixed some bugs with the designer.
And sorry, my edit number 2 didn't work as expected. I noticed my blue squiggles were gone in the xaml, but I didn't check the designer. x__x