WPF Nested Custom Markup Extension Bug Workaround in VS 2015 / 2017 - c#

Am I doing something wrong or is this the same bug that was reported in 2008?
In the XAML snippet below I am using a custom markup extension:
<Image Source="{wpfx:IconEx Fill={StaticResource mybrush},
Icon={StaticResource myicongeometry}}" />
wpfx is a prefix for my CLR Namespace that I imported in XAML.
IconEx is my custom public Markup Extension class that derives from MarkupExtension.
The image element is rendered correctly in the designer (that is the markup extension does its job), however when I try to build it in either VS 2015 or VS 2017 RC, I get this:
Error: Unknown property 'Fill' for type 'MS.Internal.Markup.MarkupExtensionParser+UnknownMarkupExtension' encountered while parsing a Markup Extension.
Note that the property Fill is public on my markup extension class, as is the class itself. If I change the values of both Fill and Icon properties to not use { } nested markup extension syntax, everything works. The problem is though that I cannot do that.
So, given that it's almost 2017 now, are there any workarounds that do not use the nested property syntax, as it looks like an overkill? Or did I do something wrong, and it;'s not a bug? Maybe I miss some attributes on my markup extension class or it's properties.

Related

XAML (WPF) Namespace?

I have been trying to read up on XAML namespace and the use of xlmnr and it has been kind of fuzzy. Either it is too technical, or too simplistic.
My question is a little similar to a question asked here, but my question has more to do with the x part attached to it.
So:
Does the xmlns:x, mean a secondary namespace? i.e. the non-default one? Can I have more than one, and if so what order does the search for the right class go in? This of course assumes that xmlns is the default one.
What about the meaning of and difference of attaching x:name as opposed to name to a tag?
Edit:
Turns out, I think I completely misunderstood it. There is no search hiearchy like C# using statement, or java's import. The xmlns:<name> is more like a way to define a name that you can access a whole tree of classes. The x on the other hand is a conventional way to define XMAL related stuff, but is not a requirement.
Can anyone confirm?
The use of XML namespaces in XAML is necessary because of the underlying XML technology used.
xmlns:x indeed creates a second namespace named x. You can reference attributes, etc from it using x:....
If you had simply use name instead of x:name it would have referenced the default namespace.
You can have as much namespaces declared in your XAML as needed.
The standard x namespace exposes common XAML features - basically a mapping of various things that are implemented in code to give them meaning in the XAML context. In the case of x:Name (not x:name - case matters) the XAML compilation process creates a code-behind field based on the x:Name value. The non-x Name property is an attribute representing the Name property on the WPF FrameworkElement base class, which in most cases works the same way as setting the x:Name, and you can't assign both on the same element. See this question for more info.
To the first part of your question: you can change the x to whatever you want, but shouldn't to maintain consistency, and can also (and will in practice) add other xmlns: declarations, primarily to access additional feature implemented in code. For example, if you work in Blend you will often see a xmlns:d added which contains a bunch of designer specific properties. Any code that you need to reference, like data types, converters, etc. will generally use an xmlns: with clr-namespace and assembly specified to map to the .NET namespace in the code: i.e. xmlns:local="clr-namespace:WpfApplication1"

T4 Text Templates Pass object to included Template

I am using Preprocessed Text Templates (.tt) . How can I pass object to another included Preprocessed Text Template? I checked the documentation but didn't find any sample to do that.
Thanks
If you look at the generated code from your preprocessed template, you'll see that it is just a partial class. A great way to pass in data is simply to add another partial of the class, and provide a member and Getter/Setter pair for it. If you then include some further code in that preprocessed template, it will contribute to the same class, so your added member will still be available. If on the other hand, your included code is just class feature clocks (<#+ #>), then you'll likely be defining methods that you can call, in which case you can simply add your data to pass as an extra parameter to those methods.

Visual Studio Text Editor Extension

I am trying to get started in Visual Studio (2010) extensions and I am having a hard time finding the right materials. I have the SDK, but the included samples seem to be things like adorners, windows, and icons.
I am trying to make an extension that will work directly with the text editor (to alphabetize all of my method names in a class, or make all constant names upper case for example) but I can't find a demo for this type of functionality, or even a tutorial.
Does anyone know where I can find this kind of stuff?
I had the exact same question and now have browsed the web several hours until I was being able to understand and explain how you'd need to start with such an extension.
In my following example we will create a small and dumb extension which will always add "Hello" to the beginning of a code file when an edit has been made. It's very basic but should give you an idea how to continue developing this thing.
Be warned: You have to parse the code files completely on your own - Visual Studio does not give you any information about where classes, methods or whatever are and what they contain. That's the biggest hurdle to be taken when doing a code formatting tool and will not be covered in this answer.[*]
For those who skipped to this answer, make sure you downloaded and installed the Visual Studio SDK first or you will not find the project type mentioned in step one.
Creating the project
Start by creating a new project of the type "Visual C# > Extensibility > VSIX Project" (only visible if you selected .NET Framework 4 as the target framework). Please note that you may have to select the "Editor Classifier" project type instead of the "VSIX Project" type to get it working, s. comment below.
After the project has been created, the "source.extension.vsixmanifest" file will be opened, giving you the ability to set up product name, author, version, description, icon and so on. I think this step is pretty self-explaining, you can close the tab now and restore it later by opening the vsixmanifest file.
Creating a listener class to get notified about text editor instance creations
Next, we need to listen whenever a text editor has been created in Visual Studio and bind our code formatting tool to it. A text editor in VS2010 is an instance of IWpfTextView.
Add a new class to our project and name it TextViewCreationListener. This class has to implement the Microsoft.VisualStudio.Text.Editor.IWpfTextViewCreationListener interface. You need to add a reference to Microsoft.VisualStudio.Text.UI.Wpf to your project. The assembly DLL is found in your Visual Studio SDK directory under VisualStudioIntegration\Common\Assemblies\v4.0.
You have to implement the TextViewCreated method of the interface. This method has a parameter specifying the instance of the text editor which has been created. We will create a new code formatting class which this instance is passed to later on.
We need to make the TextViewCreationListener class visible to Visual Studio by specifying the attribute [Export(typeof(IWpfTextViewCreationListener))]. Add a reference to System.ComponentModel.Composition to your project for the Export attribute.
Additionally, we need to specify with which types of files the code formatter should be bound to the text editor. We only like to format code files and not plain text files, so we add the attribute [ContentType("code")] to the listener class. You have to add a reference to Microsoft.VisualStudio.CoreUtility to your project for this.
Also, we only want to change editable code and not the colors or adornments around it (as seen in the example projects), so we add the attribute [TextViewRole(PredefinedTextViewRoles.Editable)] to the class. Again you need a new reference, this time to Microsoft.VisualStudio.Text.UI.
Mark the class as internal sealed. At least that's my recommendation. Now your class should look similar to this:
[ContentType("code")]
[Export(typeof(IWpfTextViewCreationListener))]
[TextViewRole(PredefinedTextViewRoles.Editable)]
internal sealed class TextViewCreationListener : IWpfTextViewCreationListener
{
public void TextViewCreated(IWpfTextView textView)
{
}
}
Creating a class for code formatting
Next, we need a class handling the code formatting logic, sorting methods and so on. Again, in this example it will simply add "Hello" to the start of the file whenever an edit has been made.
Add a new class called Formatter to your project.
Add a constructor which takes one IWpfTextView argument. Remember that we wanted to pass the created editor instance to this formatting class in the TextViewCreated method of our listener class (simply add new Formatter(textView); to the method there).
Save the passed instance in a member variable. It'll become handy when formatting the code later on (e.g. for retrieving the caret position). Also tie up the Changed and PostChanged events of the TextBuffer property of the editor instance:
public Formatter(IWpfTextView view)
{
_view = view;
_view.TextBuffer.Changed += new EventHandler<TextContentChangedEventArgs>(TextBuffer_Changed);
_view.TextBuffer.PostChanged += new EventHandler(TextBuffer_PostChanged);
}
The Changed event is called every time an edit has been made (e.g. typing a char, pasting code or programmatical changes). Because it also reacts on programmatical changes I use a bool determining if our extension or the user / anything else is changing the code at the moment and call my custom FormatCode() method only if our extension is not already editing. Otherwise you'll recursively call this method which would crash Visual Studio:
private void TextBuffer_Changed(object sender, TextContentChangedEventArgs e)
{
if (!_isChangingText)
{
_isChangingText = true;
FormatCode(e);
}
}
We have to reset this bool member variable in the PostChanged event handler again to false.
Let's pass the event args of the Changed event to our custom FormatCode method because they contain what has changed between the last edit and now. Those edits are stored in the array e.Changes of the type INormalizedTextChangeCollection (s. the link at the end of my post for more information about this type). We loop through all those edits and call our custom HandleChange method with the new text which this edit has produced.
private void FormatCode(TextContentChangedEventArgs e)
{
if (e.Changes != null)
{
for (int i = 0; i < e.Changes.Count; i++)
{
HandleChange(e.Changes[0].NewText);
}
}
}
In the HandleChange method we could actually scan for keywords to handle those in a specific way (remember, you have to parse any code on yourself!) - but here we just dumbly add "Hello" to the start of the file for testing purposes. E.g. we have to change the TextBuffer of our editor instance. To do so, we need to create an ITextEdit object with which we can manipulate text and apply it's changes afterwards. The code is pretty self-explaining:
private void HandleChange(string newText)
{
ITextEdit edit = _view.TextBuffer.CreateEdit();
edit.Insert(0, "Hello");
edit.Apply();
}
When compiling this add-in, an experimental hive of Visual Studio starts up with only our extension loaded. Create a new C# file and start typing to see the results.
I hope this gives you some ideas how to continue in this topic. I have to explore it myself now.
I highly recommend the documentation of the text model of the editor on MSDN to get hints about how you could do this and that.
http://msdn.microsoft.com/en-us/library/dd885240.aspx#textmodel
Footnotes
[*] Note that Visual Studio 2015 or newer come with the Rosyln Compiler Platform, which indeed already analyzes C# and VB.NET files for you (and probably other pre-installed languages too) and exposes their hierarchical syntactical structure, but I'm not an expert in this topic yet to give an answer on how to use these new services. The basic progress of starting an editor extension stays the same as described in this answer anyway. Be aware that - if you use these services - you will become dependent on Visual Studio 2015+, and the extension will not work in earlier versions.
just have a look at the "Getting started with Editor extensions" site on the MSDN http://msdn.microsoft.com/en-us/library/dd885122.aspx
Thorsten

Custom binding class is not working correctly

Currently I'm playing around with WPF data binding and I came to an issue I dont understand. So I post the problem here, maybe you have and idea whats geoing wrong.
At first: I'm working with Visual Studio 2008 under Windows Vista 32bit, the problem is also present in Windows 7 RC1 64bit, latest updates/service packs are installed except Vista, its still running with SP1.
Here is the problem:
I'm not able to set a ValueConverter in an inherited Binding class.
Here is my custom binding class:
public class MyBinding : Binding
{
public MyBinding() : base() { }
public MyBinding(string path) : base(path) { }
}
This class should do exactly the same as the original Binding class because currently it does not implement any own logic. I can use this class in XAML as follows:
<TextBlock Text="{local:MyBinding SomeProperty}" />
local is the namespace where the MyBinding class is implemented.
Now here comes the first thing I dont understand. VS2008 shows the following error message in its error window (the original message is in german, because I'm running a german system - i dont have the english error message, so I will try to translate)
Kein Konstruktor des MyBinding-Typs weist 1-Parameter auf.
(No constructor of type MyBinding takes 1 argument)
Althoug this error is display the project compiles just fine and the MyBinding class is working as expected. Why Visual Studio does not find the corresponding constructor (wich, I would say, is properly implemented)?
I can prevent these message if I change the XAML code to this:
<TextBlock Text="{local:MyBinding Path=SomeProperty}" />
The error message is gone because the MyBinding's default constructor is called, everything works fine, ok...
Now I would like to set a ValueConverter to my property binding, XAML looks like this:
<Window.Resources>
<local:MyValueConverter x:Key="converter" />
</Window.Resources>
[...]
<TextBlock Text="{local:MyBinding Path=SomeProperty, Converter={StaticResource converter}}" />
[...]
..., and here I get the following error while compiling (original in german and I think, I've also found the original message in english):
Beim Analysieren einer Markup Extension wurde für den Typ "MS.Internal.Markup.MarkupExtensionParser+UnknownMarkupExtension" die unbekannte Eigenschaft "Converter" gefunden. Zeile X Position Y.
(Unknown property 'Converter' for type 'MS.Internal.Markup.MarkupExtensionParser+UnknownMarkupExtension' encountered while parsing a Markup Extension. Line x position Y)
Now I cannot compile anymore because VS does not find the converter property (wich is a public property of the original Binding class).
I've managed to get the MyBinding class to run with a converter I specify, but only with a little hack:
I've added the following property to the MyBinding class:
public Type ConverterType
{
get { return Converter == null ? null : Converter.GetType(); }
set { Converter = value == null ? null : (IValueConverter)Activator.CreateInstance(value); }
}
... and XAML changes to this:
<TextBlock Text="{local:MyBinding Path=SomeString, ConverterType=local:MyValueConverter}" />
Now my project compiles and runs fine. Actually I think, its a nice solution, because you dont have to specify the converter as a static resource and the binding expression looks a little bit more clearly to me. But at the end, this cannot be the solution.
So can anyone tell me what I've done wrong? Why I cannot set the Converter property in my custom Binding class?
Thank you!
Best regards,
René
after some further testing with markup extensions, this issue passed my way over and over again and after some more googling, I think I've found a confirmation, that this is a bug in Visual Studio designer. Everyone, whos interested in that should take a look at
http://www.hardcodet.net/2008/04/nested-markup-extension-bug
Best regards,
René
Inheriting from Binding probably isn't the best solution. If you simply want to get around declaring a converter as a static resource, try creating a Singleton of your converter, and use it like so:
Text="{Binding Path=Foo, Converter={x:Static local:MyConverter.Converter}}"
Alternately, you could try a markup extension as shown here.
Thank you for your response!
In general I have no problem with the binding expression syntax and declaring the converter before using it. What I've written above is just a nice result of the workaround for my major problem. I want to create my own Binding class and pass my own converter to it the same way I would do it with the original Binding class.
I just want to understand the error message, wich is presented to me by VS. I think it must have a reason, either I'm doing something wrong or there is a bug in Visual Studio/WPF.
Until this afternoon I was pretty sure that the problem is sitting in front of the computer. But I've posted this question in two other user groups (also at MSDN in the forum for WPF). Till now you are the only person who respond. And so I came to the idea, that it also might be a problem with visual studio... I dont know.
Again, thank you very much, I will have a closer look on the page you've posted (currently just a short one).
Have a nice weekend!
Best regards,
René
I had the same problem, do not know why, but I put the custom binding on another dll and it worked.

C# property attributes

I have seen the following code:
[DefaultValue(100)]
[Description("Some descriptive field here")]
public int MyProperty{...}
The functionality from the above snippit seems clear enough, I have no idea as to how I can use it to do useful things. Im not even sure as to what name to give it!
Does anyone know where I can find more information/a tutorial on these property attributes?
I would be also interested in any novel / useful tasks this feature can do.
The functionality from the above
snippit seems clear enough,
Maybe not, as many people think that [DefaultValue()] sets the value of the property. Actually, all it does to tell some visual designer (e.g. Visual Studio), what the code is going to set the default value to. That way it knows to bold the value in the Property Window if it's set to something else.
People have already covered the UI aspect - attributes have other uses, though... for example, they are used extensively in most serialization frameworks.
Some attributes are given special treatment by the compiler - for example, [PrincipalPermission(...)] adds declarative security to a method, allowing you to (automatically) check that the user has suitable access.
To add your own special handling, you can use PostSharp; there are many great examples of using PostSharp to do AOP things, like logging - or just code simplification, such as with automatic INotifyPropertyChanged implementation.
They are called Attributes, there is a lot of information in msdn, e.g. http://msdn.microsoft.com/en-us/library/z0w1kczw.aspx
In general they don't "do" anything on their own, they are used by some other code that will use your class. XmlSerialization is a good example: XmlSerializer (provided by Microsoft as part of the framework) can almost any class (there are a number of requirements on the class though) - it uses reflection to see what data is contained in the class. You can use attributes (defined together with XmlSerializer) to change the way XmlSerializer will serialize your class (e.g. tell it to save the data as attribute instead of an element).
The ones in your example is used by the visual designer (i.e. MS Expression Blend and Visual Studio designer) to give hints in the designer UI.
Note that they are metadata and will not affect the property logic. Setting DefaultValue for instance will not set the property to that value by default, you have to do that manually.
If you for some reason want to access these attributes, you would have to use reflection.
See MSDN for more information about designer attributes.
We use it to define which graphical designer should be loaded to configure
an instance of a specific type.
That is to say, we have a kind of workflow designer which loads all possible command
types from an assembly. These command types have properties that need to be configured,
so every command type has the need for a different designer (usercontrol).
For example, consider the following command type (called a composite in our solution)
[CompositeMetaData("Delay","Sets the delay between commands",1)]
[CompositeDesigner(typeof(DelayCompositeDesigner))]
public class DelayComposite : CompositeBase
{
// code here
}
This is information is used in two places
1) When the designer creates a list of commands, it uses the CompositeMetaData
to display more information about the command.
2) When the user adds a command to the designer and the designer creates
an instance of that class, it looks at the CompositeDesigner property,
creates a new instance of the specified type (usercontrol) and adds it
to the visual designer.
Consider the following code, we use to load the commands into our "toolbar":
foreach (Type t in assembly.GetExportedTypes())
{
Console.WriteLine(t.Name);
if (t.Name.EndsWith("Composite"))
{
var attributes = t.GetCustomAttributes(false);
ToolboxListItem item = new ToolboxListItem();
CompositeMetaDataAttribute meta = (CompositeMetaDataAttribute)attributes
.Where(a => a.GetType() == typeof(Vialis.LightLink.Attributes.CompositeMetaDataAttribute)).First();
item.Name = meta.DisplayName;
item.Description = meta.Description;
item.Length = meta.Length;
item.CompositType = t;
this.lstCommands.Items.Add(item);
}
}
As you can see, for every type in the assembly of which the name ends with "Composite",
we get the custom attributes and use that information to populate our ToolboxListItem instance.
As for loading the designer, the attribute is retreived like this:
var designerAttribute = (CompositeDesignerAttribute)item.CompositType.GetCustomAttributes(false)
.Where(a => a.GetType() == typeof(CompositeDesignerAttribute)).FirstOrDefault();
This is just one example of how you might be able to use custom attributes,
I hope this gives you a place to start.
These attributes customize the design time experience.
http://msdn.microsoft.com/en-us/library/a19191fh.aspx

Categories