Any way to create a global piece of code to run on the initialisation of all Windows like there you can create global properties for XAML through App.xaml?
I'm just curious as the piece of code I'm using relates specifically to interface but can't be set in xaml so must be in code so I have to write it into the constructor of each Window. Just wondering if there might be a work around.
you can solve this problem with the concept of inheritance create Base class that inherits Window do your common stuff in that class . All of Windows that want this common functionality will inherit the base class.
Base class
public class MyBaseWindow : Window
{
//do your common stuff in this base class for all windows
protected object MyProperty { get; set; }
}
.cs
public partial class MyWindow : MyBaseWindow
{
xaml
<local:MyBaseWindow x:Class="WpfApplication1.MyWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MyWindow" Height="300" Width="300">
I hope this will give you an idea.
Related
I have several WPF UserControls. Each of these controls implement an interface IStepEditor
The class declaration is as follow:
public partial class EditorLoadCsv : UserControl, IStepEditor { ... }
IStepEditor is not very important, but it is currently defined as follow:
public interface IStepEditor
{
StepConfig Save();
void Load(StepConfig config);
}
I then have several classes holding those controls, like this:
public class StepConfigController
{
public IStepEditor EditorControl { get; }
}
All of this is working as expected when I use IStepEditor all around, but to add those controls to a WPF window from a StepConfigController, I eventually have to cast them in a UserControl, like this:
((StackPanel)panEditorControl).Children.Add(currentControl as UserControl);
Since the IStepEditor implementation is actually a UserControl, it works. I could add checks for that cast, but the whole idea seems wrong. I cast an object to another very unrelated object through some weak relationship I trust others to follow.
I tried to create an abstract class inheriting from both UserControl and IStepEditor and have my actual UserControls derive from that, but since the WPF UserControls are partial classes, it didn't work. It was something like this:
public abstract class StepEditorControl : UserControl, IStepEditor
{
abstract public StepConfig Save();
abstract public Load(StepConfig config);
}
So this class was legit and compiled, but trying to derive from it in WPF failed.
public partial class EditorLoadCsv : StepEditorControl
{
}
This code generates:
error CS0263: Partial declarations of 'EditorLoadCsv' must not specify different base classes
Which is right, because the xaml markup still references a UserControl. Trying to change the xaml markups from UserControl to a StepEditorControl failed, but it could be the proper solution to the whole problem. I also tried to implement a WPF Custom Control Library, but it seemed like a lot of work just to implement an interface with 2 methods.
The XAML is generated automagically through Visual Studio designer:
<UserControl x:Class="MyNamespace.EditorLoadCsv"
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"
xmlns:local="clr-namespace:MyNamespace"
mc:Ignorable="d"
d:DesignHeight="50" d:DesignWidth="623.077">
<!--- Actual UserControl content ---!>
</UserControl>
So an answer to either of these questions could solve my problem:
1- How to avoid a (possibly) dangerous dynamic cast when implementing WPF UserControl with custom interfaces?
2- How to get WPF XAML markup to accept a custom class instead of UserControl?
3- How to refactor code to avoid this ugliness in the first place?
The Panel.Children property is a UIElementCollection, so anything that should be added needs to be a UIElement, which is the base class of all WPF UI components.
Do not use the as operator, but simply cast your editor objects to UIElement. If any of them is by accident not a UIElement, you would correctly get an InvalidCastException.
((Panel)panEditorControl).Children.Add((UIElement)currentControl);
In order to create a UserControl-derived base class for all your StepEditors, you did the first step correctly:
public abstract class StepEditorControl : UserControl, IStepEditor
{
public abstract void Load(StepConfig config);
public abstract StepConfig Save();
}
However, the XAML of a control derived from StepEditorControl would have to look like this:
<local:StepEditorControl
x:Class="MyNamespace.EditorLoadCsv"
xmlns:local="clr-namespace:MyNamespace"
...>
...
</local:StepEditorControl>
I am aware that there are other questions posted that appear to be the same issue but none of them fix my issue.
I'm new to WPF I'm trying to convert a program from WinForms to WPF. I have a main window, "Kproj.Forms.frmLogin", that inherits a base class, "Kproj.Forms.frmSwitch", that inherits the System.Windows.Window class. WhenI got the above issue, my initial XAML code was:
<Control:frmSwitch x:Class="Kproj.Forms.frmLogin"
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:Control="clr-namespace:Kproj.Forms"
mc:Ignorable="d"
Title="LOG IN" Height="309" Width="678">
<Grid Height="271" Width="662">
... Content
</Grid>
</Control:frmSwitch>
with these in the code-behinds:
namespace Kproj.Forms
{
public partial class frmLogin : frmSwitch
{
}
}
namespace Kproj.Forms
{
public partial class frmSwitch : Window
{
}
}
Upon further research, I found out that I needed to make frmSwitch into a base class with no XAML. Thus, I created frmSwitch2 in just general Class form that looks like this:
namespace Kproj.Forms
{
public class frmSwitch2 : Window
{
}
}
I then adjusted the main window XAML accordingly:
<Control:frmSwitch2 x:Class="Kproj.Forms.frmLogin"
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:Control="clr-namespace:Kproj.Forms"
mc:Ignorable="d"
Title="LOG IN" Height="309" Width="678">
<Grid Height="271" Width="662">
... Content
</Grid>
</Control:frmSwitch2>
and the main window code-behind to:
namespace Kproj.Forms
{
public partial class frmLogin : frmSwitch
{
}
}
Now, I lost the original error message, but I gained a message that states
"The name 'frmSwitch2' does not exist in the namespace 'clr-namespace:FITS.Forms'."
even though it suggests "frmSwitch2" when I type "Control:" in the main window XAML, so it knows it does exist in the namespace. Any suggestions?
Disclaimer: I tried researching it as best as possible but all the posts I found on StackOverflow were this issue but all were fixed by converting from XAML\cs partial classes to solo code-behind full XAML-less class.
After looking into what the inheritance actually wanted, I learned that the only purpose of the inheritance was for variables so I was able to make it work but just converting them to static global variables and accessing them directly. I ended up not needing the inheritance after all.
If anyone else, that ends up knowing more MVVM, does come across a fix for this issue, it would be nice to know it. Even though I no longer need it, it would be good learning.
I am having WPF form which is inherited with FormBase.cs which is of type Window. Now I change normal forms inheritance with this created FormBase.cs base class. But now problem is every time partial class which is inherited with FormBase.cs automatically change to default inheritance which is Windows in every change in form. And I found
Partial declarations of 'Wpf_Fomrs.MainWindow' must not specify different base
this error while compiling code.
Code:
[System.ComponentModel.DesignerCategory("")]
public class FormBase : Window, IFormBase // Base class
{
}
[System.ComponentModel.DesignerCategory("Form")]
public partial class MainWindow : FormBase // Created normal form
{
}
//Auto generated partial class which again inherited with `Window` class
public partial class MainWindow : System.Windows.Window, System.Windows.Markup.IComponentConnector {
}
// I want this result every time.
public partial class MainWindow : System.Windows.Markup.IComponentConnector {
}
While using Win Forms I dont find such problem.
What is problem with code generation logic in WPF forms?
EDIT
XAML of MainWindow looks like
<Window x:Class="Wpf_Forms.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Form1" Height="350" Width="525" SizeToContent="WidthAndHeight" xmlns:my="clr-namespace:Foundation.ControlsWpf;assembly=Foundation" Loaded="Window_Loaded" Topmost="True" WindowState="Maximized">
I've been facing an error that tells me that the partial declarations must not specify a different base class.
public partial class MainWindow : Shape
{
public MainWindow()
{
InitializeComponent();
this.Stretch = System.Windows.Media.Stretch.Fill;
this.StrokeLineJoin = PenLineJoin.Round;
}
I get error from :
public partial class MainWindow : Shape
The 'MainWindow' gives me error about the specifying of a different base. How do i go about rectifying this error?
My XAML currently, is the default one:
<Window x:Class="Triangle.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
</Grid>
</Window>
I have yet to edot anything from the XAML as this codes are codes i found somewhere from online and is using it to try out whether or not it work.
MainWindow normally extends Window.
So in your code-behind you'll see public partial class MainWindow : Window, and in your associated XAML you'll see something like:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
... />
...
</Window>
To extend another class (not sure what Shape is, but I'm assuming it's appropriate in this case), you'll have to correct your XAML in addition to the code-behind... something like this:
<Shape x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
... />
...
</Shape>
MainWindow : Shape? I suppose it to be MainWindow : Window
do please verify the base class (root element) from the designer of the MainWindow.xaml and use the same base class here.
typically top level window classes like default MainWindow class derives from Window. whereas in your case I can see it is being derived from Shape
if you are trying to create a shape class then there is no InitializeComponent() in shape class and it does not need a designer hence a partial class is not required. last but not the least the class name MainWindow does not sounds a nice name for the same. you may perhaps revise it.
your main page should be in the format
public sealed partial class MainPage : Page
inheriting only Page Class.
I'm sure this is easy, but new to me for WPF using C#. I know about inheriting from classes and have done so many times such as in C# WinForms projects...
public class MyClass : DerivedFromClass
{}
However, stumped in WPF and here's the issue. I want to build my own set of controls to be used as a baseline for a new learning project... preset my own styles, colors, backgrounds, and other functionality. No problem. Start first with a WPF Window and create "MyWindow".
Now, I want to take this baseline "MyWindow" and subclass THAT for yet another class of MySubClassedWindow. So, I create a new Window class, and by default, VS2010 builds the both designer and code portions of the form. I do view code on the MySubClassedWindow and find
partial class MySubclassedWindow : Window
{}
In C# using WinForms, I would just change to (and I've included the class library reference that includes the "MyWindow" declaration.
partial class MySubclassedWindow : MyWindow
{}
When I do, I get a compilation error of
Partial declarations of 'MyNameSpace.MySubclassedWindow' must not specify different base classes
Your base class should just be a class file (not a Window).
So create WindowBase.cs
public class WindowBase : Window
{
// ...
}
In MainWindow (for example) change the xaml.cs file to inherit from WindowBase instead
public partial class MainWindow : WindowBase
{
public MainWindow()
{
InitializeComponent();
}
// ...
}
In MainWindow.xaml, include the namespace for WindowBase and change Window to base:WindowBase like this
<base:WindowBase x:Class="SubclassWindow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:base="clr-namespace:NamespaceForWindowBase"
Title="MainWindow" Height="350" Width="525">
<!--...-->
</base:WindowBase>
Having a base Window class brings a critical drawback, namely that binding to properties in your base class is much more difficult to do (and the currently accepted answer does not solve this problem). What's the point of inheriting if you cannot reference base properties? I have figured out how to set this up after some long hours, and wanted to share in the hopes that others will be spared this pain.
You may need to use things like value converters, which can only be referenced via static binding, which in my case made sense to have in the WindowBase class. I have included an example because I found it difficult to use these converters consistently in both design and run mode.
You cannot set the x:Name property of this inherited Window via XAML, but you may not need to do so if using the below approach. I have included an example of how to set the name, because inheriting from Window will not allow you to set the name at design time in the subclass. I do not recommend relying on the name of the window at design time, but setting d:DataContext should take care of any binding needs for you.
Be warned that in design mode, but not run mode, a copy of WindowBase (or the class specified in d:DataContext) will be instantiated in design mode and used as the binding context. So in very specific cases you may see data discrepancies, but in the vast majority of use cases this approach should suffice.
WindowBase.cs
````
public class WindowBase : Window
{
//User-Defined UI Configuration class containing System.Drawing.Color
//and Brush properties (platform-agnostic styling in your Project.Core.dll assembly)
public UIStyle UIStyle => Core.UIStyle.Current;
//IValueConverter that converts System.Drawing.Color properties
//into WPF-equivalent Colors and Brushes
//You can skip this if you do not need or did not implement your own ValueConverter
public static IValueConverter UniversalValueConverter { get; } = new UniversalValueConverter();
public WindowBase()
{
//Add window name to scope so that runtime properties can be referenced from XAML
//(Name setting must be done here and not in xaml because this is a base class)
//You probably won't need to, but working example is here in case you do.
var ns = new NameScope();
NameScope.SetNameScope(this, ns);
ns["window"] = this;
//Call Initialize Component via Reflection, so you do not need
//to call InitializeComponent() every time in your base class
this.GetType()
.GetMethod("InitializeComponent",
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance)
.Invoke(this, null);
//Set runtime DataContext - Designer mode will not run this code
this.DataContext = this;
}
//Stub method here so that the above code can find it via reflection
void InitializeComponent() { }
}
SubClassWindow.xaml
<local:WindowBase
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:YourProjectNamespace"
x:Class="YourProjectNamespace.SubClassWindow"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type= {x:Type local:WindowBase}, IsDesignTimeCreatable=True}"
Title="SubClassWindow" Height="100" Width="300">
<!--Design-time DataContext is set in d:DataContext. That option does not affect runtime data binding
Replace local:WindowBase with local:SubClassWindow if you need to access properties in SubClassWindow-->
<Grid Background="{Binding UIStyle.BackgroundColor, Converter={x:Static local:WindowBase.UniversalValueConverter}}"></Grid>
</local:WindowBase>
Nothing is needed in the SubClassWindow code behind (not even a constructor).