The specified value cannot be assigned to the collection - c#

Edit
This bugs me for an almost year. I'll update the answer and add bounty.
I've custom control, which has dependency property
public class Graph : Control
{
public List<Figure> Figures
{
get { return (List<Figure>)GetValue(FiguresProperty); }
set { SetValue(FiguresProperty, value); }
}
public static readonly DependencyProperty FiguresProperty =
DependencyProperty.Register("Figures", typeof(List<Figure>), typeof(Graph),
new PropertyMetadata((d, e) => ((Graph)d).InvalidateVisual()));
...
}
Figure is the base class for all figures:
public abstract class Figure { ... }
public class LineFigure : Figure { ... }
public class XGridFigure : Figure { ... }
public class YGridFigure : Figure { ... }
...
Now look at screenshots below to see the problem: sometimes (after doing a change to xaml in other place) designer goes crazy about it and stop rendering the whole window, throwing exceptions, while code compiles and runs without problem. I can close this xaml (designer) and open it again to make problem go away. But it always reappears.
Question: is there something wrong on my side? Missing attribute? Wrong usage? How can I fix that problem?
Old question
Ugly situation.
I have 2 UserControl. In both hand-made control Graph is used. Graph has property Figures to specify List<Figure>. There are dozens of figures which have Figure as base.
In one UserControl it works fine, in other throws exception
The specified value cannot be assigned to the collection. The following type was expected: "Figure".
And I fail to see a difference what could cause a problem.
Here is problematic one screenshot
And here is working one
Despite of errors project compiles and runs, but if I need to do modification to problematic UserControl, then it's not showing any content (says "Invalid Markup"). Graphs are nearly the same, all 8 errors are shown for to just one UserControl.
What should I do? How to troubleshoot such errors? I exclude (completely) any problem with Graph because it runs without a single problem AND it works without problem for another UserControl. Visual Studio designer problem? Using 2013 Express for Windows Desktop.

Indeed the visual designer does not recognize the inheritance from Figure. One solution is to use IList as the Interface type:
public IList Figures
{
get
{
return (IList)GetValue (FiguresProperty);
}
set
{
SetValue (FiguresProperty, value);
}
}
public static readonly DependencyProperty FiguresProperty =
DependencyProperty.Register ("Figures", typeof (IList), typeof (Graph), new PropertyMetadata (new List<object>()));
That might look like a bit strange (because you give up type safetyness). But have a closer look at the WPF classes. They all do it that way (most likely for good reasons). Or WPF even creates collection classes like PathFigureCollection that implement both IList and IList<PathFigure>.

close the project, restart VS and reopen it. does it still list the errors? visual studio often seems to report "phantom errors", but they usually go away if you close and restart etc.

If the custom control is in the same solution or project, Visual Studio builds it (when it considers it necessary) so it can use the control in the designer.
Sometimes this built/cached version gets out of sync with the code files which causes the Xaml parser/syntax checker to get confused and display those wavy red lines.
I have had success with closing and reopening all designers that use the control but that is pretty annoying to keep on doing. In my experience the most reliable solution is to move the control into a separate solution and project and set a 'proper' reference to the dll.

I had a whole load of these errors in one project.
Eventually I found that the project did not have a reference to System.Xaml.
Adding a reference to System.Xaml removed all of the warnings.
The strange thing is that it didn't cause a runtime problem.

Related

C# rule for public fields

I have problem with public fields, which I use from time to time in my code. I keep forgeting to change them to private and create properties for them- especialy when Im testing some new part of code (and Im used to create public field for testing at first).
I was thinking that it would be fine to see some sort of "warning" if I use public field in my code.
I have found out, that I can create a ruleset (Im using Visual Studio Community 2013) and choose any of the rule I need. I searched for the rules relative to public fields and found these 2: CA2211: Non-constant fields should not be visible and CA1051: Do not declare visible instance fields. I checked these in the ruleset, tried to Run code analysis on whole solution but I cant see any warnings in the outcome.
I even tried to add something like public int i; in one of my classes but still nothing.
Do you know if I have the right rules or whether there is something else I should do to get the warning? Thank you.

How to specify order of debugger visualizers in Visual Studio

I've been working on a debugger visualizer for Visual Studio for some time and while the actual visualizer works fine. The problem is that it always places itself at the top of the visualizer list when examining a variable which really annoys some of the users who rather have Text as the top one (since the top one is also default when opening VS).
I can't find any support for this on DialogDebuggerVisualizer or DebuggerVisualizerAttribute which were my first thoughts so I've been scouring SO/MSDN/Google for information on how to affect the sort order of the visualizers (preferably to put mine last in the list) but to no avail.
Below is how I register my visualizer, it then just shows a form based on the value that is being visualized.
using Microsoft.VisualStudio.DebuggerVisualizers;
[assembly: System.Diagnostics.DebuggerVisualizer(
typeof(Shorthand.VSAddins.JsonVisualizer.JsonVisualizer),
typeof(VisualizerObjectSource),
Target = typeof(string),
Description = "Json Visualizer")]
namespace Shorthand.VSAddins.JsonVisualizer
{
public class JsonVisualizer : DialogDebuggerVisualizer
{
protected override void Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider)
{
var json = objectProvider.GetObject() as string;
var form = new VisualizerForm { Json = json };
windowService.ShowDialog(form);
}
}
}
Does anyone know if it is possible to affect the order of the visualizers or should I just let it be?
I don't think there is a solution. But there is a workaround:
Define your own Text Visualizer and put appropriate DebuggerVisualizer attribute before the attribute of your JsonVisualizer. The result will be that string will be readable by default and Json Visualizer can be chosen. A window with a multi-line textbox is not too much work.
It is probably not even necessary to write visualizer. It should be possible to use internal one but I don't know its name (Which class is used for "Text Visualizer"?).
It will always appear first, by design. The under the hood cast has found the best match for the variable it is reflecting on.
however, you could do either of two things. You could make the visualizer only appear when the sting contains ':'
Or you could use reflection to reorder the visualisers by adding them to the end of the collection in the order you want, then removing the originals from the collection.
For the latter you will most likely have to change the collection from readonly to writable. Via reflection.
There is no reliable source to draw on other than your will to succeed.
I guess that VS 'under the hood' can distinguish between type of string and type of xml quite easily, but Xml is just a string too, so a key question here would be, how does VS tell the difference between the two?
Could you dissect the VS XML visualizer to see how it works (even if you have to use reflector on the DLL to do it, you might get to see the method that works it out)

Custom CollectionEditor doesn't serialize to aspx code

Context
I've been working on a custom collection editor / designer for a custom ASP.Net web control. The web control exposes a strange hierarchy, so a custom editor seemed like the right thing to do to make it easier for developers.
Building ASPX code and using the web control works. In other words, things like PersistChildren and ParseChildren are taken care of.
The signature of the property in the web control looks something like this:
[PersistenceMode(PersistenceMode.InnerProperty)]
[Themeable(false)]
[Browsable(false)]
public virtual DimensionsCollection Dimensions { get; internal set; }
Note that the property is not public; if it were public, all kinds of things in the designer will go wrong. DimensionsCollection is a class that simply inherits List<Dimension>. The Dimension class itself is nothing fancy, just a thing with some properties.
Just because I think it looks cool, I want to be able to modify the property from an action in the designer. To do that, I implemented a ControlDesigner class and added an ActionList. One of the actions there is a linkbutton that opens an editor:
var editor = new Editors.DimensionEditor(control.Dimensions);
if (editor.ShowDialog() == DialogResult.OK)
{ /* SEE BELOW */ }
The editor itself is a windows form that takes a List<Dimension> as constructor argument and modifies the collection.
Problem
When I use this code, I can see that the editor works and that the control collection is updated in the 'designer' view. If I open the editor multiple times, the state changes, meaning that somewhere in memory the state is updated by the editor.
However, if I go to the ASPX code, I can see that the Dimensions are not there anymore. So, the problem in a nutshell is that I somehow have to tell Visual Studio to write/serialize/persist the property to the ASPX file. (simple as that...)
Strangely, I cannot find anywhere how to do this... even though a normal CollectionEditor seems to be capable of doing just that (which I cannot subclass unfortunately)
Some things I tried
For other properties I noticed you have to use something like this, but this doesn't seem to work. Code was entered at the point marked as 'see below' or in some cases to a helper call in the designer called from that point:
PropertyDescriptor pd = TypeDescriptor.GetProperties(base.Component)["Dimensions"];
// use setter with internal property -> no effect
// this.OnComponentChanged(this, new ComponentChangedEventArgs(this.Component, pd, null, newdim)); -> no effect
// use getter to obtain list -> populate that using another list that's created in the editor
I can understand why it doesn't work; apparently someone has to tell Visual Studio that the property has changed... I just don't know how to do just that.
This was really a pain to figure out with apparently no sources online that explain how to do this.
Basically you want to use the OnComponentChanging / Changed methods to notify the designer. And apparently the designer uses transactions for the rest of the logic. (My guess is that it has to do with undo/redo behavior). For a normal type this is done automatically when you use the PropertyDescriptor, for collections it apparently doesn't wrap the collection which means you have to do it manually.
To solve the issue, you need to create a small method like this in either the UITypeEditor or in the DesignerActionList class your implementing:
private void ChangeAction(List<Dimension> newDimensions)
{
IDesignerHost host = GetService(typeof(IDesignerHost)) as IDesignerHost;
PropertyDescriptor pd = TypeDescriptor.GetProperties(typeof(MyControl))["Dimensions"];
var dimensions = (DimensionsCollection)pd.GetValue(control);
var trans = host.CreateTransaction();
IComponentChangeService ccs = (IComponentChangeService)GetService(typeof(IComponentChangeService));
ccs.OnComponentChanging(control, pd);
dimensions.Clear();
dimensions.AddRange(newDimensions);
ccs.OnComponentChanged(control, pd, null, dimensions);
trans.Commit();
}
If you're implementing a UITypeEditor, make sure to use context.Instance from EditValue as the control and the given provider to lookup the services.

Visual Studio 2010 keeps changing my winforms control

I have an odd situation with a user control in VS 2010. The form designer keeps changing my entry and then telling me it does not exist! It compiles and runs the first time, and then if I change something unrelated, it gives me an error in the designer.cs file (Cannot resolve symbol SomeEntry).
private SomeEntry someEntry;
// ...
this.someEntry = new **MyNameSpace**.SomeEntry();
if I remove the MyNameSpace.
this.someEntry = new SomeEntry();
it works, until I make a change again. If I look at the class when the mouse is over the changed designer file, SomeEntry shows SomeEntry.SomeEntry()
instead of MyNameSpace.SomeEntry()
Basically, the definition is something like this:
namespace MyNameSpace
{
public partial class SomeEntry : FormValidatingUserControl
{
public SomeEntry()
{
InitializeComponent();
}
}
}
So, what do I do?
It turns out that I should have posted my code EXACTLY as it appeared, as I am sure someone would have figured this out for me sooner.
The issue was that I was trying to simplify for the post, and changed the names of MyNameSpace and SomeEntry to keep it generic.
The project is something the namespace is something (so far, normal) and there was a generated class something from the entity framework.
To reproduce the problem, I created a new project called WinFormTestX. So, the solution is WinFormTestX and the project WinFormTestX. I added a class called WinFormTestX, but did nothing with it.
namespace WinFormTestX
{
public class WinFormTestX
{
public int ID { get; set; }
}
}
Now, I create a UserControl (UserControl1) and drop a simple button on it. Compile it, and the toolbox adds this control, as expected. Now, I drop it on Form1 and compile it and get an error:
Error 1 The type name 'UserControl1'
does not exist in the type
'WinFormTestX.WinFormTestX' D:\Data\Projects\Temp\WinFormTestX\Form1.Designer.cs 31 51 WinFormTestX
As soon as I right click on the class WinFormTestX and Exclude From Project (or delete it), everything works.
So, just having the class in the project of the same name as the namespace, even when it is not used, causes an issue. Obviously, now that I know the cause, there is a simple way around this. But, is this something that is a "bug" that should be submitted to Microsoft?
I've had stuff like this happen when manually moving a class into a new namespace. If you're not careful, your class can become defined multiple times. For example, there may be a residual designer .cs file that still defines the class in its old namespace or some other .cs/.designer.cs mismatch. In other words, your assembly may contain both a SomeEntry.SomeEntry and MyNameSpace.SomeEntry class.
Check the Visual Studio object browser to see if you have SomeEntry defined in multiple namespaces.

C#: Attrbute for intellisense to show method only outside of assembly

Basically what I'm hoping for is something that would work like how the Obsolete attribute works with Intellisense and strikes the method text when typing out the name. What I'm looking for is an attribute that blocks the method from being seen with the assembly it's defined. Kind of like an reverse internal. Using 3.5 by the by.
Yeah sounds odd but if you need the reason why, here it is:
My current solution for lazy loading in entity framework involves having the generated many to one or one to one properties be internal and have a facade? property that is public and basically loads the internal property's value:
public ChatRoom ParentRoom
{
get
{
if(!ParentRoomInnerReference.IsLoaded)
{
ParentRoomInnerReference.Load();
}
return ParentRoomInner;
}
set
{
ParentRoomInner = value;
}
}
Problem with this is if someone tries to use the ParentRoom property in a query:
context.ChatItem.Where(item => item.ParentRoom.Id = someId)
This will blow up since it doesn't know what to do with the facade property when evaluating the expression. This isn't a huge problem since the ParentRoomInner property can be used and queries are only in the entity assembly. (IE no selects and such in the UI assembly) The only situation comes in the entity assembly since it can see both properties and it's possible that someone might forget and use the above query and blow up at runtime.
So it would be nice if there were an attribute or some way to stop the entity assembly from seeing (ie blocked by intellisense) the outward facing properties.
Basically inside the assembly see ParentRoomInner. Outside the assembly see ParentRoom. Going to guess this isn't possible but worth a try.
I do see that there is an attribute
for stopping methods from being
viewable
(System.ComponentModel.EditorBrowsable)
but it's choices are rather slim and
don't really help.
You can use the EditorBrowsableAttribute for this:
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public void MyMethod() {}
One thing to know, though: In c#, you will still get intellisense on the method if it is in the same assembly as the one you are working in. Someone referencing your assembly (or your project, for a project reference) will not see it though. You can also pass EditorBrowsableState.Advanced, and then you will only get intellisense if c# if you clear the HideAdvancedMembers option in Tools Options.
I haven't heard of a good way to do this in plain .NET. But, here are some ideas. Maybe one of them will work, or set you off in a direction that will be helpful.
Use FxCop, probably writing your own rule to make sure ParentRoom isn't called from the asslembly that defined it.
Look into the various post-processing projects for .NET (link design-by-contract).
Write some code inside your ParentRoom getter which will check the stack (using "new Stack()" or "new StackFrame(1)" to figure out whether the caller was from the same assembly. If so, either throw an exception or simply return ParentRoomInner.

Categories

Resources