Community Toolkit MVVM - Placing WPF Window XAML files in a Views folder? - c#

I have a question for people familiar with the Community Toolkit MVVM regarding best practices for building up the Views part of MVVM. I have started a new project to try to get things figured out before trying to implement this into my actual project. My main question is, if you have multiple views/windows for different purposes in a WPF application, is it not a good idea to place them into a View or Views folder? If so, I'm having a hard time getting the application to launch the main window.
System.IO.IOException: 'Cannot locate resource 'wpf_mvvm_test.views.mainwindow.xaml'.'
The first thing I tried was just moving the MainWindow.xaml file to the views folder, which caused the runtime error as soon as it compiled. I started changing the namespace references for the MainWindow.xaml, MainWindow.xaml.cs, App.xaml, App.xaml.cs, as well as the startup URI to reflect the namespace for the folder, WPF_MVVM_Test.Views, and none of the changes I have made have prevented the error. I did leave the App.xaml file in the main project, not in the folder. If I try to move it into the Views folder, even if I change its x:Class and the App.xaml.cs namespace to WPF_MVVM_Test, when I try to run it, it gives me an error that there is no static Main entrypoint.
Is there no way to place the WPF window files into a folder? If it's not possible, it's not possible, but if it is possible, I would love to figure out how, as it would make it easier to keep the solution organized.
MainWindow.xaml:
<Window x:Class="WPF_MVVM_Test.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPF_MVVM_Test.Views"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
</Grid>
</Window>
MainWindow.xaml.cs:
using System.Windows;
using WPF_MVVM_Test.ViewModels;
using WPF_MVVM_Test.Views;
namespace WPF_MVVM_Test.Views
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
}
}
App.xaml:
<Application x:Class="WPF_MVVM_Test.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPF_MVVM_Test"
StartupUri="WPF_MVVM_Test.Views.MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
App.xaml.cs:
using System.Windows;
using WPF_MVVM_Test.Views;
namespace WPF_MVVM_Test
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}

Thanks to ASh for the very helpful reply. I'm not sure what is preventing the application from compiling by moving the MainWindow.xaml file in to a folder, but the workaround references ASh provided definitely works.
First, I removed the StartupUri statement from the App.xaml file.
Second, in the App.xaml.cs file, I added an override for an OnStartup event as shown below, ensuring the folder that the MainWindow files are located in is in the using statements.
App.xaml.cs
using System.Windows;
using WPF_MVVM_Test.Views;
namespace WPF_MVVM_Test
{
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
new MainWindow().Show();
}
}
}

Related

Derive cs class from a wpf-class with xaml which is in another assembly

I have a base class like that in the project A
namespace WpfApplication1
{
/// <summary>
/// Interaktionslogik für Layer.xaml
/// </summary>
public partial class Layer
{
public Layer()
{
InitializeComponent();
}
}
}
with this xaml (in my project it has a complex tooltip, but for simplicity I changed it to a TextBlock)
<Canvas x:Class="WpfApplication1.Layer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Canvas.ToolTip>
<TextBlock Text="ToolTip"/>
</Canvas.ToolTip>
</Canvas>
For testing purpose I want to derive from that in my TestAssembly
using WpfApplication1;
namespace WpfApplication2
{
public class TestingLayer : Layer
{
}
}
But when I start I get the the
The component `TestingLayer` does not have a resource identified by the URI `/WpfApplication1;component/layer.xaml`
I already googled and found some threads related to that problem, but with some differences:
The component does not have a resource identified by the uri
This one suggests to make a wrapper around TestingLayer but unfortunately this doesn't work for me because I want to get access to some protected funtions (especially to OnRender whose access I can't modify). Furthermore the OP wants a derived control with xaml, and this is a big difference to my needs, because my derived class has no xaml. This difference also applies to these threads
Best practice to resolve the URI error
https://support.microsoft.com/en-us/kb/957231
Since the derivation works when I create TestingLayer in my project A I think there is just a problem in the URI. But I don't know how to solve it.
To sum it up: How to derive a c# class with only a cs file from a control (with xaml) from another assembly?

How do I reconnect a XAML view file with it's code behind file?

I find very frequently that while I'm 'prototyping', and I change the base type of the code behind class, or something like that, that the two files become completely unaware of each other. Example:
XAML:
<UserControl x:Class="G4S.XTime.Modules.Employees.Details.Views.EmployeeGridView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
...
Code-behind:
namespace G4S.XTime.Modules.Employees.Details.Views
{
public sealed partial class EmployeeGridView: UserControl
{
public EmployeeGridView()
{
//InitializeComponent();
}
}
}
The call InitializeComponent produces a compile time error, saying it doesn't exist.
This disconnect phenomenon happens often enough to be costing me time, and I often just copy the code out of both files, delete the view, add a new view with the same name, paste the same code back, and everything works.
What am I missing that connects the two files? In the project file, I see the code-behind depends on the XAML, so I think if I comment out InitializeComponent, then compile with only the XAML, I will have the other part of my code-behind partial class. But this does not work. It doesn't seem to compile the XAML at all unless there is a code behind.
What can I do to reconnect these two files, in most cases?
Edit your project file and make sure you have something similar to this:
<Compile Include="EmployeeGridView.xaml.cs">
<DependentUpon>EmployeeGridView.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
For me the problem was caused by not having the correct way of including the files in the csproj file.
incorrect:
<CodeAnalysisDictionary Include="Windows\ConnectionSecuritySettings.xaml">
correct:
<Page Include="Windows\ConnectionSecuritySettings.xaml">
This happened when I moved the items to a new project
Make sure the declaration at the top of the xaml matches the code behind file with the full path including namespace.
eg. If namespace name is "MyControls" and Code behind Class is "MyNewControl" then
xaml declaration should be something like ..
<UserControl x:Class="MyControls.MyNewControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
Height="41" Width="77"
>
and code behind would be ..
namespace MyControls
{
/// <summary>
/// Interaction logic for MyNewControl.xaml
/// </summary>
public partial class MyNewControl: UserControl
{
#region Constructors
public MyNewControl()
{
InitializeComponent();
}
#endregion
}
}
I had the same problem (InitializeComponent could not be found) after a cut-paste of my XAML. The answer suggested here solved my problem. The suggestions is, in the Properties window of the XAML, change the Build Action to Page. Apparently the copy-paste can change the Build Action to Resource.
Hope this helps!
[Edit] I just wanted to add that this was also after updating the namespace for both the code-behind and in the xaml:
x:Class="NewNamespace.CodeBehindClass"

WPF Resource Dictionary using code behind file can’t be found

When I include an assembly containing a ResourceDictionary using the following pack syntax:
"pack://application:,,,/WpfCore;component/ResourceDictionaries/ThemedControls.xaml"
It works as expected, but as soon as I add a code behind file to the XAML of the ResourceDictionary, the following error is thrown:
“An error occurred while finding the resource dictionary”
The code behind is added to the XAML in the usual way:
< ResourceDictionary x:Class="com.mycompany.WpfCore.ResourceDictionaries.ThemedControls"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
</ResourceDictionary>
and looks like this:
namespace com.mycompany.WpfCore.ResourceDictionaries
{
public partial class ThemedControls : ResourceDictionary
{
public ThemedControls ()
{
InitializeComponent();
}
}
}
Intuition tells me this is a namespace problem, but all the variations I've tried fail. What am I doing wrong or is this a limitation of WPF ResourceDictionaries?
Edit:
Seems the question detail was called out and found to be wanting.
The initial example had the namespace simplified. The default namespace for the WpfCore project is com.mycompany.WpfCore which I have now added into the code examples above.
The ThemedControls.xaml and ThemedControls.xaml.cs files are located in a subfolder called ResourceDictionaries within the WpfCore project folder.
The resulting assembly is used as a referenced assembly in another solution and this is where the Pack URI is being used.
Edit 2:
After playing around with the build action for the xaml files (changing from page to resource and back again) things started working. Marking Sheridan's answer as correct.
I don't think that you have declared your ResourceDictionary quite correctly... the application name really should be in the namespace. This should work... at least it works for me:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Class="WpfCore.ResourceDictionaries.ThemedControls">
</ResourceDictionary>
Code behind:
namespace WpfCore.ResourceDictionaries
{
public partial class ThemedControls : ResourceDictionary
{
public ThemedControls()
{
InitializeComponent();
}
}
}

Setting <Window.DataContext> in XAML

I followed a very simple MVVM example as a basis for my program. The author had one code behind instruction he used in the main page to set the DataContext. I'm thinking I should be able to do this in the XAML instead. The MainWindowViewModel is in a directory ViewModels. The code behind works.
namespace RDLfromSP
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModels.MainWindowViewModel();
}
}
}
I can't seem to find the right combo to set it instead in the XAML
<Window x:Class="RDLfromSP.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="300" Width="300" >
<Window.DataContext>
<local:ViewModels.MainWindowViewModel />
</Window.DataContext>
Thanks in advance for your help
You'll need an xml namespace mapping to the ViewModels namespace. Once you add that, it would be:
<Window.DataContext>
<vms:MainWindowViewModel />
</Window.DataContext>
(This is assuming you map vms to the appropriate namespace.)
This should look just like your current namespace mapping for local:, but called vms: with the appropriate namespace specified.

Why is Application.OnStartup not being called?

I have a WPF .NET 4 application where I override the OnStartup method in order to process the file passed to my application. However, it seems that this method is not being called when the application runs. I put an exception in there and even a breakpoint and it starts up and completely ignores this.
Am I missing something?
Code for App.xml.cs:
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
throw new NotImplementedException();
}
}
Contents of App.xaml:
<Application x:Class="XGN_Image_Downloader.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
EDIT: Found it! The x:Class attribute in App.xaml did not match the App.xaml.cs class :) That's what you get for coding while drinking wine. (Thanks to this thread: WPF app startup problems)
Found it, I had to set the x:Class attribute in App.xaml to the same class as the App.xaml.cs class. This was an error caused by bad refactoring on my side.
x:Class must be filled with the namespace and exact class name on App.xml.cs
Eg: <Application x:Class="Namespace.ClassName"

Categories

Resources