WPF's Use of Partial Classes' Access Modifiers
While writing a reusable component for a client, I placed it in a different assembly and began to change all of the non-public classes' access modifiers to internal. Building the project, I received the following error:
error CS0262: Partial declarations of 'ClassName' have conflicting accessibility modifiers.
The two conflicting source files were my original ClassName.xaml.cs file and the automatically generated ClassName.g.cs file. It appeared that the ClassName.g.cs stated that my class was still public. Here are my types:
MyWindow.cs:
internal partial class MyWindow : Window
MyWindow.g.cs:
public partial class MyWindow : System.Windows.Window, System.Windows.Markup.IComponentConnector
After a bit of digging, I found the culprit. Apparently, when you have a non-public modifier, you have to qualify your element with the x:ClassModifier attribute. In my case, the code looked like this:
<Window x:Class="MyNamepsace.MyWindow" x:ClassModifier="internal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
All works and all is well in the world... Well, not everything. You see, this is both ugly and easily avoidable.
Why is this ugly? The x:ClassModifier attribute clearly states that the string passed to it:
[...] varies, depending on the code-behind programming language being used.
This makes your XAML file's correctness bound to the language the code-behind is written in, rather than be language-neutral and CLR-centric.
Another assumption made by WPF's design team was that the default value is public, which means every type is added to the list of publicly visible types in your assembly by default. If you write a client application, this may not be of any concern to you, but if you write reusable components, this is a highly important design decision. On the other hand, this might just be me nitpicking.
How could this be avoided? As you may well know, when defining a partial class, the definition is collected from every part, glued together, and only then are default behaviors appended and the code is compiled. This means that if you fail to write an access modifier in one file and only write it in another, there will be an access modifier, but on the other hand, writing two conflicting modifiers will cause a compiler error.
This means that the only thing needed to be done to avoid the entire need for the x:ClassModifier attribute was to emit generated code with no access modifier and have the code-behind implicitly take control of it.
Final words: This can also be found in base class references, where all partial classes are marked as deriving from the same base type, as you can see in the examples above. Then again, this may just be a safeguard against people messing with their base classes... who knows.
I hope this would go away in the next version of the designer. Is anyone listening?