|
I'll provide more details:
Got 3 classes & 1 interface
1 class that has all the functionality and implements an interface
1 class that makes that class generic, has 1 property named DataItemTypeName and inherits from above class
1 class that wraps the generic class so it's usable in a webpage and also inherits from the first class.
in the controldesigner, I'm trying to access the control I made through the property Component which runtimetype is the type of the generic class.
What I understood from the exception is that it's trying to cast class nr 2 to the interface that it's baseclass implements and fails.
When I get to a line of code that says:
ICustomRepeater control = (ICustomRepeater)Component;
I get the exception below:
System.InvalidCastException was unhandled by user code
HResult=-2147467262
Message=Unable to cast object of type 'CustomRepeaterNS.CustomGenericItemsControl`1[TestApp.DummyTestClass]' to type 'CustomRepeaterNS.ICustomRepeater'.
Source=CustomRepeater
StackTrace:
at CustomRepeaterNS.CustomRepeaterDesigner.GetDesignTimeHtml() in d:\CustomRepeater\CustomRepeater\CustomRepeater.cs:line 842
at System.Web.UI.Design.ControlDesigner.GetDesignTimeHtml(DesignerRegionCollection regions)
at CustomRepeaterNS.CustomRepeaterDesigner.GetDesignTimeHtml(DesignerRegionCollection regions) in d:\CustomRepeater\CustomRepeater\CustomRepeater.cs:line 807
at System.Web.UI.Design.ControlDesigner.GetViewRendering(ControlDesigner designer)
InnerException:
|
|
|
|
|
Well either there's something else going on, or I've not understood your class hierarchy.
The following simplified version of what I think you're describing works perfectly:
interface ICustomRepeater { }
class CustomGenericItemsControl : ICustomRepeater { }
class CustomGenericItemsControl<T> : CustomGenericItemsControl { }
class DummyTestClass { }
class Wrapper : CustomGenericItemsControl
{
public CustomGenericItemsControl<DummyTestClass> Component
{
get { return new CustomGenericItemsControl<DummyTestClass>(); }
}
}
static void Main()
{
Wrapper wrapper = new Wrapper();
ICustomRepeater control = (ICustomRepeater)wrapper.Component;
Console.WriteLine(control);
}
From your error message, it would seem that the CustomGenericItemsControl<T> doesn't implement the ICustomRepeater interface, and doesn't inherit from a class that implements the ICustomRepeater interface.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Ended up fixing this problem by using delegates instead of interfaces, here is a sample of my code:
private Dictionary<string,Func<ITemplate>> templategetproperties;
private Func<ITemplate> GetITemplateProperty(string name)
{
if(templategetproperties==null)
{
templategetproperties = new Dictionary<string, Func<ITemplate>();
}
if(templategetproperties.ContainsKey(name)==false)
{
PropertyInfo pinfo = componentruntimetype.GetProperty(name);
templategetproperties[name] = (Func<ITemplate>)Delegate.CreateDelegate(typeof(Func<ITemplate>), Component, pinfo.GetGetMethod());
}
return templategetproperties[name];
}
Used Action instead of Func for the setters.
I think the problem was that the method MakeGenericType of the Type class doesn't transfer the interfaces of the non generic class type to the generic class type. This is only an educated guess though.
|
|
|
|
|
If I understand you correctly, you need to explicitly implement the interfaces (this is the correct term for it):
interface IFoo
{
int Baz {get; set;}
}
interface IBar
{
int Baz {get; set;}
}
class Quux : IFoo, IBar
{
int _fooBaz;
int _barBaz;
int IFoo.Baz
{
get { return _fooBaz; }
set { _fooBaz = value; }
}
int IBar.Baz
{
get { return _barBaz; }
set { _barBaz = value; }
}
}
To Access:
Quux quux = new Quux();
var stuff = (IFoo)quux.Baz
var stuff = (IBar)quux.Baz;
Hopefully I've got that right...
|
|
|
|
|
Thanks mate, always wondered what that option implement explicitly meant, now I know.
Your solution fixed my problem, so thanks so much.
|
|
|
|
|
|
Found out it didn't really fix the problem. Apparantly if I close Visual Studio and restart it, the problem is fixed. Well until I change something in the code, then I have to restart Visual Studio again. Kinda really annoying to restart VS every time I make a change to code.
My structure is as follows, changed the names a bit for more transparancy:
public interface ICustomItemsControl : IDataBoundControl, IComponent
{
}
public class CustomItemsControl : DataBoundControl, ICustomItemsControl
{
}
public class CustomItemsControl <TDataItem> : CustomItemsControl, ICustomItemsControl
{
private CustomItemsControlItem <TDataItem> CreateItem(int itemIndex, ListItemType itemType, bool dataBind, TDataItem dataitem)
{
return new CustomItemsControlItem <TDataItem>(itemIndex, itemType);
}
}
public class CustomItemsControlItem : CompositeControl
{
}
[ControlBuilder(typeof(CustomGenericItemControlBuilder))]
[Designer(typeof(CustomRepeaterDesigner))]
public class TypedCustomItemsControl : CustomItemsControl , ICustomItemsControl
{
private string dataItemTypeName;
[PersistenceMode(PersistenceMode.Attribute)]
public string DataItemTypeName
{
get { return dataItemTypeName; }
set { dataItemTypeName = value; }
}
}
The RepeaterControlBuilder converts the CustomRepeater class to a generic class.
I think the problem might be in the following class that does the actual work to convert my CustomItemsControl to a generic CustomItemsControl:
internal class RepeaterFakeType : TypeDelegator
{
public RepeaterFakeType(Type dataItemType)
: base(typeof(CustomItemsControl<>).MakeGenericType(dataItemType))
{
this.repeaterItemType = typeof(CustomGenericItemsControlItem<>).MakeGenericType(dataItemType);
}
protected override PropertyInfo GetPropertyImpl(string name, BindingFlags bindingAttr, Binder binder,
Type returnType, Type[] types, ParameterModifier[] modifiers)
{
PropertyInfo info = base.GetPropertyImpl(name, bindingAttr,binder,returnType,types,modifiers);
if (info == null)
return null;
if (name == "ItemTemplate" || name == "AlternatingItemTemplate")
info = new FakePropertyInfo(info, this.repeaterItemType);
return info;
}
}
|
|
|
|
|
Can't help you there, something else is going on. Sounds very like VS has broken though, or it's hanging on to something between builds. Definitely not the desired behaviour though!
|
|
|
|
|
I have a subclass of Windows.Forms.Label that I'd like to serialize to XML without using IXmlSerializable. A windows control (a Label in this case) isn't serializable.
Consider the following...
public class SubLabel : Windows.Forms.Label
{
public Text {get; set;}
public int LocationX {get; set;}
public int LocationY {get; set;}
public void Save(string path)
{
XmlSerializer xs = new XmlSerializer(typeof(SubLabel));
using (StreamWriter sw = new StreamWriter(path))
{
xs.Serialize(sw, this);
}
}
public static SubLabel Load(string path)
{
XmlSerializer xs = new XmlSerializer(typeof(TestClass));
using (StreamReader sr = new StreamReader(path))
{
return (SubLabel)xs.Deserialize(sr);
}
}
...
}
All I want to serialize are the public properties above.
I'd like to keep it simple by using the Save() and Load() methods above.
Of course this fails because of the Label parent class.
Is there an easy way to do this?
|
|
|
|
|
You could copy the selected public properties (Text , LocationX , LocationY ) to a separate class and just serialize that. Your Load() method would then deserialize that class and return a new SubLabel with those properties set.
/ravi
|
|
|
|
|
Hello
I am developing a program for a community launcher/downloader
what i am here to ask is there libraries to download a repo through an autoconfig file for downloading and updating the mod
I want the user to be able to download from this repo ftp://62.210.148.145/public/.a3s/autoconfig and to download and put these ftp://62.210.148.145/public in a game directory
The autoconfig is in an .gz file
That's the file in a nutshell it doesn't have an extention
|
|
|
|
|
Help with which part? Sounds almost like you expect the library to do everything your app should do?
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
A Point in the right direction
|
|
|
|
|
|
hello,
I have a click method for a button and try to iterate through all comboboxes on the form. When I try to access the control through the Controls collection the program jumps out of the method (in the line Control cc = this.Controls[i];). My code is below. Can anyone tell me what I'm doing wrong here?
public partial class NewTopicCtxCfgElemFrm : Form
{
private bool _freeConfig = false;
public NewTopicCtxCfgElemFrm()
{
InitializeComponent();
}
public void Initialize(Topic topic)
{
_freeConfig = business.TopicFactory.GetTopicTypeIsFreeConfigurable(topic.ID);
label1.Text = (_freeConfig) ? "Please select at least one of all." : "Please select all.";
List<TopicTypeObjType> list = business.TopicFactory.GetObjTypeForTopic(topic.ID);
int k = 0;
foreach (var item in list)
{
int y = GetNewLocationTop(k);
Label lbl = new Label();
lbl.Text = item.ObjTypeName;
lbl.Location = new Point(10, y);
lbl.Width = 200;
this.Controls.Add(lbl);
ComboBox cbx = new ComboBox();
cbx.Location = new Point(220, y);
cbx.Width = 200;
cbx.Tag = item;
this.Controls.Add(cbx);
List<Xerox.CDMG.XControls.XDataItem> objects = business.ObjLinkFactory.GetObjForObjType(item.ObjTypeID);
cbx.DataSource = objects;
cbx.SelectedIndex = -1;
k++;
}
Button btn = new Button();
btn.Text = "Save";
btn.Location = new Point(10, GetNewLocationTop(k));
btn.Width = 200;
this.Controls.Add(btn);
btn.Click += new EventHandler(btn_Click);
}
void btn_Click(object sender, EventArgs e)
{
try
{
bool checkRequiredObjTypesOk = !_freeConfig;
for (int i = 0; i < this.Controls.Count; i++)
{
Control cc = this.Controls[i];
ComboBox cb = cc as ComboBox;
if (cb != null)
{
if (!_freeConfig)
{
if (cb.SelectedIndex == -1) { checkRequiredObjTypesOk = false; }
}
else
{
if (cb.SelectedIndex > -1) { checkRequiredObjTypesOk = true; }
}
}
}
}
catch (Exception exc)
{
Logger.LogException(exc);
}
}
private int GetNewLocationTop(int k)
{
return k * 25 + label1.Top + label1.Height + 30;
}
}
|
|
|
|
|
Curious - what do you mean it jumps out? On which iteration of the loop - the first?
Regards,
Rob Philpott.
|
|
|
|
|
It differs, most of time on the first loop, sometimes in the second loop. I do not get any exception. I tried restarting visual studio, did not help. Also tried fornext(), but same result.
|
|
|
|
|
Well, I'm as confused as you. I can't see anything wrong with the code, and particularly not anything which would cause it to return from the function on that line.
The only very long shot I can think of is the pdbs are out of date of something and that's causing the debugger to lie to you.
Regards,
Rob Philpott.
|
|
|
|
|
pdbs??? could you elaborate please?
|
|
|
|
|
I really don't think that would be it, but, when you compile your exe it'll produce some .PDB files. These are the 'program database' files and are used by the debugger to map the execution point and variables etc. into the source code.
If it gets out of sync then you can see some very weird behaviour.
When execution leaves your button handler, does the application carry on?
Regards,
Rob Philpott.
|
|
|
|
|
How could i put the pdb file back in sync? I already tried a complete rebuild but that didn't help.
|
|
|
|
|
Do a "Clean Project" first, then recompile it.
|
|
|
|
|
You could try a complete rebuild of your project and then put a breakpoint at the beginning of the btn_Click method and run it through your debugger. You should also review what that method is trying to do. As it stands it seems to be setting checkRequiredObjTypesOk randomly to true or false , but never uses that value for any purpose.
|
|
|
|
|
That part was not finished yet.
|
|
|
|
|
OK. However I have just tested your code (modified to fit my sample) and it works fine using both for and foreach . You need to get to work with your debugger to see what is happening. I suspect some out of date code is getting linked in by mistake somewhere.
|
|
|
|