Access created UI Elements in XAML WPF - c#

I Have
class Canvas2:Canvas
{
}
class created in the same namespace. i can't use Canvas2 in XAML.
how can i make Canvas2 accessable in XAML code?
Im a newby.

Define the xmlns like xmlns:local="clr-namespace:WpfApplication1" assuming Canvas2 is define in namespace WpfApplication1.
then you can use Canvas2 as <local:Canvas2 x:Name="MyCanvas"/>
Thanks

you have to import your local namespace to the XAML too.
Check the MSDN for sample.

A quick and dirty answer: Add the following line to your AssemblyInfo.cs
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "YourNamespace")]
This way you add all classes in your Namespace to the default WPF-XML-Namespace. Then you can use your classes directly without adding an custom xml namespace.
Warning: Even if this works, it is not the recomended way. Especially I would not recommend this for larger projects because it could easily lead to name conflicts.
The correct way is to add a custom XML namespace like nit and AsitK described.

Related

Why can't I use partial root namespace?

I have a compiled class library with a root namespace Protege.MyLibrary.
It has a few root types, for example, CommonlyNamedType.
When I add the library to my consuming application, I'd like, for clarity in some situations, to be able to specify variables as:
using Protege;
...
MyLibrary.CommonlyNamedType oMyType = new MyLibrary.CommonlyNamedType;
rather than
using Protege.MyLibrary;
...
CommonlyNamedType oMyType = new CommonlyNamedType;
The former doesn't compile, indicating for the namespace Protege "Using directive is unnecessary", and that is can be removed.
This seems bizarre as I could go the other way and add additional namespaces, such as Protege.MyLibrary.AnotherNamespace.
I seem to be able to do this 100% okay in VB.NET - using either or both Imports Protege and/or Protege.MyLibrary and even optionally qualifying types with redundancy. But not in C#.NET.
I have had a good look around SO and other places and haven't seen an explanation for this behavior. Any ideas?
You can statically import a class like
using static System.IO.File;
It doesn't support for class, you need to use normal using for import the namespace.

Without having the ability to change them, how can you avoid this XAML-caused namespace collision?

Unfortunately, due to issues that are frustratingly out of my control, I'm forced to use components with namespaces which I cannot change. Because of the way they have structured them, it's causing collisions in the generated code-behind.
Again, unfortunately, I do not have access to the code which defines these namespaces so they cannot be changed. Down-voting this does not help anyone, especially without a reason/explanation. Also, I've also tried demonstrating the issue to the owners explaining why this is a very bad design, but I've been told for other reasons, changing them is not an option, so I'm forced to find a work-around.
Here's a simplified example to illustrate the issue. Consider a solution with two projects, a 'Core' library, and the consuming application:
Items in 'Core' Library
ModelA (Namespace: SomeFeature.Core.Models)
ModelB (Namespace: SomeFeature.Core.Models)
**Items in 'ConsumingApp' (References 'Core') **
MainWindow (Namespace: ConsumingApp.SomeFeature)
TestControl (Namespace: SomeFeature.Controls)
The cause of the collision can be explained in three steps:
SomeFeature is both the root of one namespace, and a child of another
TestControl is defined as being in the rooted version of the namespace (same as the library), not the one MainWindow is in.
Code-generation ends up placing the generated variables for those XAML elements in the namespace scope of MainWindow, not that matching what's actually in the XAML.
Now if these were manually-defined variables in non-generated code-behind, dealing with this is easy. By simply adding the prefix global:: it 'roots' the namespace you're typing, thus removing all ambiguity.
namespace ConsumingApp.SomeFeature{
public partial class MainWindow{
// Note the 'global::' prefix
global::SomeFeature.Controls.TestControl MainTestControl { get; set; }
}
}
The above will ensure that it always resolves relative to the global SomeFeature namespace and never the nested ConsumerApp.SomeFeature namespace. Pretty straight forward.
However, the auto-generated code-behind from the XAML parser doesn't include that global:: prefix, so in the generated code, you actually get this:
namespace ConsumingApp.SomeFeature{
public partial class MainWindow{
// Note: without the 'global::' prefix, this resolves to
// 'ConsumingApp.SomeFeature.Controls.TestControl'
// which doesn't actually exist, causing the mentioned issue.
SomeFeature.Controls.TestControl MainTestControl { get; set; }
}
}
Which results in this error:
Error CS0234 The type or namespace name 'Controls' does not exist in the namespace 'ConsumingApp.SomeFeature' (are you missing an assembly reference?)
As noted in the code comments, this is because it's not looking for this class path...
SomeFeature.Controls.TestControl
but rather this one:
ConsumingApp.SomeFeature.Controls.TestControl
which doesn't exist, ergo the error.
The fix would be to somehow get the auto-generated code to explicitly output the global:: but I don't know how to do that, or even if it can be done.
Things I've tried:
Arguing for them to change their namespaces! (I lost!)
Explicitly referencing the assembly in the XAML import:
Defining aliases in the non-generated code-behind
Searching for aliases in the XAML world (not found)
Avoiding naming the element, and instead manually searching for the control via other properties. (Horrible, but this does work!)
So is there anything that can be done here to get the code-generator to include the 'global::' prefix, or is there another way to do this?

Enforce Global Namespace in XAML

In XAML, a custom namespace can be imported with an xmlns directive:
xmlns:custom="clr-namespace:GreatStuff"
In C#, that namespace can be imported with
using GreatStuff;
Moreover, evaluation of that namespace based on the global (root) namespace can be enforced as follows:
using global::GreatStuff;
How can I enforce evaluation based on the global namespace in XAML?
Background:
I am facing the (admittedly slightly obscure) situation that there is such a namespace global::GreatStuff, which contains a WPF control class named ... GreatStuff (i.e. fully qualified, that's global::GreatStuff.GreatStuff in C#). In the same namespace, I want to use that control in a WPF window.
Interestingly, in this constellation, I cannot use the Name/x:Name attribute on any controls of type global::GreatStuff.GreatStuff in my XAML file for the window:
The type name 'GreatStuff' does not exist in type 'GreatStuff.GreatStuff'. (CS0426)
Note that the very same file compiles fine if I do not specify a Name/x:Name attribute!
Now, why should the compiler assume that by setting a Name/x:Name attribute, I am trying to access something called GreatStuff.GreatStuff.GreatStuff?
The answer can be found by examining the .g.cs file generated from the window XAML file. In that file, the XAML snippet
<custom:GreatStuff x:Name="stuff"/>
gets compiled to the following C# snippet:
internal GreatStuff.GreatStuff stuff;
That is, the fully-qualified name is used, but without the explicit global namespace marker.
Of course, as a field in a class in namespace global::GreatStuff, all of this is wrapped in
namespace GreatStuff {
And so, the poor C# compiler cannot help but assume that stuff is supposed to be of a type global::GreatStuff.GreatStuff.GreatStuff. This could be avoided if in
xmlns:custom="clr-namespace:GreatStuff"
I could enforce that any mentions of that namespace prefix could be converted while enforcing the global namespace.
For reasons external to this question, changing the namespace and/or class names is not an option here.
This issue only occurs when all of the following are true:
You have a class with an identical name as the namespace containing it.
Within that same namespace, you have a xaml file with an instance of an object that is also declared within that namespace.
That specific object instance is given a Name or x:Name attribute.
If you cannot modify anything to make any one of those conditions false, then you are working with some very serious restrictions.
As far as I know, this is a limitation of the xaml compiler, and you will need to contact Microsoft about resolving it. The only other thing I can think of would be to try to work around it with a custom build process that builds xaml, allows you to edit the generated files, then builds the code. That would require some research to figure out how to set up.

Where does the code for WPF a window/usercontrol resource go?

I'm trying to follow this tutorial, but I'm not clear on where the code for the EnumMatchToBooleanConverter class is supposed to go. I assumed that it would go in the code-behind file (i.e. view.xaml.cs), but then I get an error along the lines of The type EnumMatchToBooleanConverter was not found when I try declaring the resource in the XAML.
In general, a small WPF project should have the following approximate folder structure:
ProjectName
Converters
DataAccess
DataTypes
Images
ViewModels
Views
Converters is the folder where you should store your Converter classes. After developing WPF for a while, you'll find that your collection of Converter classes will increase in size. Each of these folders contain classes that we map to related namespaces. In the case of the Converter classes, it would typically be like this:
namespace ProjectName.Converters
{
[ValueConversion(typeof(bool), typeof(Brush))]
public class BoolToBrushConverter : IValueConverter
{
...
}
}
For the DataTypes classes, you'd use something like:
namespace ProjectName.DataTypes
{
public class SomeDataType
{
...
}
}
As #LordTakkera correctly mentioned, you'd then need to reference these classes in XAML by defining a XAML namespace like so:
xmlns:Converters="clr-namespace:ProjectName.Converters"
Then you could define the Converter in the Resources section like this:
<Converters:BoolToBrushConverter x:Key="BoolToBrushConverter" />
See the Data Conversion section of the Data Binding Overview page on MSDN for more information. The IValueConverter interface page on MSDN is another useful resource.
EnumMatchToBooleanConverter in this case is its own class. You should be able to declare it in a existing code behind, but I would stick it into its own file just to be sure.
Visual Studio can be dumb when finding resources, so you should rebuild the project in case errors are still shown.
Converters (like all other classes) belong in their own file.
Then, you just need to include the namespace in your XAML:
xmlns:local="clr-namespace:MyNamespace"
Also, try rebuilding/running the app as the XAML "intellisense" often won't update what is in the namespaces until a build has taken place.

How do I use nested namespaces for custom controls?

I have defined a user control, ExpressionControl, under the namespace:
TriggerEditor.UserControls
I have a form, "IfEditor", under the namespace:
TriggerEditor.Forms
When I add an instance of my control to the form (naming it expCondition), the following code is generated in the Designer to create the control:
this.expCondition = new TriggerEditor.UserControls.ExpressionControl();
This results in the following compilation error:
The type name 'UserControls' does not exist in the type 'TriggerEditor.Forms.TriggerEditor'
I don't understand why it is looking in "TriggerEditor.Forms.TriggerEditor"; that's not what the code says. Now, I can resolve this error manually by modifying the line, removing the "TriggerEditor." that preceeds "TriggerControls", as such:
this.expCondition = new UserControls.ExpressionControl();
This satisfies the compiler, however I obviously don't want to do this every time I add an instance of my ExpressionControl to a form. How do I avoid this situation?
It looks like you might have a TriggerEditor class within the TriggerEditor.Forms namespace; is this the case?
If so, because the TriggerEditor class is within your current namespace, you are "closer" to this class, and therefore it is looking for a subclass.
Avoid using the same name for a class and a namespace!?
Apparently, in the namespace TriggerEditor.Forms, you have a class named TriggerEditor in the same namespace as your IfEditor class.
So, when looking for TriggerEditor.UserControls.ExpressionControl, the compiler looks in the TriggerEditor class (which is in the same namespace, so closer) instead of the TriggerEditor namespace...
Normally, to avoid that, you would use a namespace alias qualifier, but being in a Designer generated class, you can't really control that.

Categories