Using Visual Studio 2022, C#, WPF, .NET Framework 4.7.2 project.
Is there any way to select XAML files at build time, such as based on either build configuration or compilation symbols, or anything else?
The use case: My now mature product was designed to run on a 2K landscape screen, all the UI layout is done in XAML and it auto-adjusts to screen sizes to a reasonable degree. However, I was just given the requirement to make a version that runs on an 800x1200 portrait screen. So, I'm going to have to completely re-design the layout of the screen, BUT it will have all the same objects and functionality. The layout changes are so drastic, and the complexity of the UI is such that it only makes sense to select completely different XMAL. I used the idea in the 2nd post here, to essentially chop my XAML file in half, copy/paste to the second half and change the layout, but because this is a runtime check, at compile time I get a zillion "xyz is already defined..." due to the duplicate objects with the same name, so unfortunately it didn't work for my case. Are there any other ideas short of creating a whole new Visual Studio project with new XAML files but sharing .cs files with the original project?
I assume you mean run-time? You should detect the screen or let the user select a layout. Then dynamically load the related resource dictionary and merge it into the App.xaml resource dictionary. Depending on the build action you can retrieve XAML files using the APIs of
ResourceManager, orApplication, orAssembly, or open the file from the filesystem. Then load it using theXamlReaeder, so that you have the finalResourceDictionaryinstance that you can add to the application's merged dictionray.The following example is concept or pseudo code:
App.xaml
DefaultLayoutResources.xaml
PortraitLayoutResources.xaml
App.xaml.cs
Making the
MainWindowcontent dynamicWindowis aContentControland therefore supports data templating. You define eachDataTemplate(e.g. one for each layout style) in a resource dictionary of the actual layout.Each layout style must have its own root resource dictionary (see example above). Then organize the resources the way you want and merge them into their related root dictionary.
For example, the portrait mode layout is defined by the PortraitLayoutResources.xaml resources. You merge all resources that belong to that layout style to the resource dictionary of PortraitLayoutResources.xaml. Like shown in the above example. All you need are styles and templates.
Then you have to differentiate between static and dynamic layout. The static layout references the dynamic layout resources using
{Dynamicresource}. The resource keys must be the same across all layout styles. This way the static layout can use fixed resource keys. But the resource that they reference will change dynamically, e.g. based on the layout style. You can search for articles and information about theming in WPF. All this is highly dynamic so that the user can switch between layouts while the application is running.The following example shows a working concept to switch the content of the
MainWindowat runtime:github example
MainWindow.xaml
App.xaml
DefaultLayoutResources.xaml
The root resource dictionary for the default layout.
DefaultLayoutMainWindowResources.xaml
PortraitLayoutResources.xaml
The root resource dictionary for the portrait layout.
PortraitLayoutMainWindowResources.xaml
LayoutStyleResourceKeys.cs
LayoutMode.cs
MainWindow.xaml.cs