Problem Creating Instances of ASP.NET User Controls Programmatically - c#

I am able to create controls pro grammatically using the code below without issue:
FileListReader fReader = (FileListReader)LoadControl("~/Controls/FileListReader.ascx");
phFileLists.Controls.Add(fReader);
However, I would like to change the control so that I can give it a constructor like this:
public FileListReader(Int32 itemGroupId, Int32 documentType, String HeaderString, String FooterString, bool isAdminUser)
{
base.Construct();
this.itemGroupId = itemGroupId;
this.documentType = documentType;
this.HeaderString = HeaderString;
this.FooterString = FooterString;
this.isAdminUser = isAdminUser;
}
and then I should be able to call the control like this:
FileListReader fReader = (FileListReader)LoadControl(typeof(FileListReader), new Object[] { itemGroupId, 6, "Sell Sheets", "<br /><br />", isAdminUser });
However, when I do this I always get an error that my in page controls within my FileListReader Control have not been instantiated and I get a null reference error. So for example I have an <asp:Label></asp:label> control that errors out when I try to set it's text on the Page_Load method. What is causing this? I figured the base.Construct() would have solved this issue but it obviously has not.

The proper way to inherit a constructor is like this:
class FileListReader : WebControl
{
public FileListReader(Int32 itemGroupId,
Int32 documentType,
String HeaderString,
String FooterString,
bool isAdminUser) : base() // <-- notice the inherit
{
this.itemGroupId = itemGroupId;
this.documentType = documentType;
this.HeaderString = HeaderString;
this.FooterString = FooterString;
this.isAdminUser = isAdminUser;
}
// ... other code here ... //
}
Does changing your constructor like that fix the issue?

I am not sure that calling base.Contruct() is what you should be doing, try calling the default contructor of the base class example below:
public FileListReader(Int32 itemGroupId, Int32 documentType, String HeaderString, String FooterString, bool isAdminUser) :base()
{
base.Construct();
this.itemGroupId = itemGroupId;
this.documentType = documentType;
this.HeaderString = HeaderString;
this.FooterString = FooterString;
this.isAdminUser = isAdminUser;
}

Related

How to resolve: Cannot implicitly convert system.collections.generic.list to system.collections.generic.ienumerable

I get this error
Cannot implicitly convert System.Collections.Generic.List to System.Collections.Generic.IEnumerable
when trying to use a list to build out #Html.DropDownList() in a page built using C# Razor.
There is a C# class called SubProgram.cs with the following method that returns a List<>:
public List<SubProgram> SubProgramCodeDescriptionList()
{
List<SubProgram> SubPrograms = new List<SubProgram>();
// Get the list of SubPrograms for this AcctIII role_code from BudgetAcct3ToSubProgram table
using (var db = Database.Open("DBNAME"))
{
string sql = #"
SELECT l.SubProgramID, l.SubProgram + ' ' + l.SubProgramDesc AS SubProgramDesc
FROM BARF_SubPrograms l
WHERE l.Deleted = 0
ORDER BY l.SubProgramDesc";
var ListSubPrograms = db.Query(sql);
foreach (var SubProgram in ListSubPrograms)
{
SubProgram item = new SubProgram ();
item.SubProgramID = SubProgram.SubProgramID;
item.SubProgramCodeDescr = SubProgram.SubProgramDesc;
SubPrograms.Add(item);
}
db.Close();
return SubPrograms;
}
}
Here is the SubProgram class this method is a part of:
public class SubProgram
{
private int subprogramid;
private string subprogramcode;
private string subprogramcodedescr;
public int SubProgramID
{
get { return subprogramid; }
set { subprogramid = value; }
}
public string SubProgramCode
{
get { return subprogramcode; }
set { subprogramcode = value; }
}
public string SubProgramCodeDescr
{
get { return subprogramcodedescr; }
set { subprogramcodedescr = value; }
}
}
In the C# section of a Razor page, I create an object of type SubProgram to fill the SubProgramList:
// Create List boxes variable need for this add
List<SubProgram> SubProgramIDdropdownlist = new List<SubProgram>();
// Create SubProgram object so the method can be called
SubProgram subProgram = new SubProgram();
// Pass object to method SubProgramIDdropdownlist to return all of the SubPrograms
SubProgramIDdropdownlist = subProgram.SubProgramCodeDescriptionList();
In the body section of the HTML page below this C# Razor section above, I try to populate the DropDownList with the above code:
<label class="FieldLabels">"Search SubPrograms"</label>
#Html.DropDownList("SubProgramCodes",
SubProgramIDdropdownlist,
new {
#id = "Column1",
#class = "EditTextBox",
}
)
In this last section, the error occurs on SubProgramIDdropdownlist and this is where I get the error
Cannot implicitly convert System.Collections.Generic.List to System.Collections.Generic.IEnumerable
There are other related posts, but not coming from a class method. Please help, I know this needs to probably use a cast, but not even sure where to begin to get this to cast correctly.
Two ways I can think of:
On Razor Page using AsEnumerable
#Html.DropDownList("SubProgramCodes",SubProgramIDdropdownlist.AsEnumarable(),new { #id = "Column1", #class = "EditTextBox"})
OR
Change the return type from List<SubProgram> to IEnumerable<SubProgram>
public IEnumerable<SubProgram> SubProgramCodeDescriptionList(){...}
Thank you tontonsevilla, your answer was helpful in solving this.
The final solution I came up with is that there was a conflict between two namespaces that both contained SelectListItem in both of them: System.Web.Mvc and System.Web.WebPages.Html.
Since I am primarily using Razor pages and not MVC for this project, I removed the #using System.Web.Mvc at the top of the Razor C# page because the error made it clear that SelectListItem is found in both System.Web.Mvc and in System.Web.WebPages.Html and I clearly needed to use one or the other, but not both. I was able to cast these to get them to work, but this was just a lot of extra code that was not needed when I realized it was a name conflict.
Using both namespaces created a conflict between these two namespaces because SelectListItem appears to be in both namespaces.

Overwrite RouteValues from asp-all-route-data in AnchorTagHelper

When using TagHelpers with MVC Core (2.1) it is possible to define asp-all-route-data and additional asp-route-x. But if x is alreay contained inside the object passed to all-route-data, an exception is thrown:
An element with the key 'x' already exists in the RouteValueDictionary
Is it possible to change this behavior (extend TagHelper, custom TagHelper, etc) to just update the value in this case instead of trying to create a new entry.
So this:
if(RouteValueDictionary.HasKey(x))
RouteValueDictionary[x] = value;
instead of (probably something like) this:
RouteValueDictionary.Add(x, value);
(Basically the if in my code isn't even necessary in an assignment like this)
Edit (maybe to explain the use case): There is an object with all the query parameters for a form, but there are also links that should basically send the same data and change a value. Submitting the form would only work if using javascript with an onclick for every link, setting the hidden input and submitting the form. But I would prefer not using JS for this as features like "middle click to new tab" will be lost.
The Answer from Tseng is very useful, however if it's necessary to use an Object for the Values and not the context it might not work that well.
In the end we created a TagHelper that only creates the query parameters:
[HtmlTargetElement("a", Attributes = RouteValuesDictionaryName)]
[HtmlTargetElement("a", Attributes = RouteValuesPrefix + "*")]
public class SearchLinkTagHelper : TagHelper
{
private const string RouteValuesDictionaryName = "my-all-route-data";
private const string RouteValuesPrefix = "my-route-";
private const string Href = "href";
private IDictionary<string, string> _routeValues;
public override int Order => 1;
[HtmlAttributeName(RouteValuesDictionaryName, DictionaryAttributePrefix = RouteValuesPrefix)]
public IDictionary<string, string> RouteValues
{
get => _routeValues ?? (_routeValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase));
set => _routeValues = value;
}
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.Attributes.TryGetAttribute(Href, out var href);
var fixedRouteValues = new Dictionary<string, string>();
foreach (var (newKey, value) in _routeValues.Where(r=>!string.IsNullOrWhiteSpace(r.Value)))
{
var key = fixedRouteValues.Keys.FirstOrDefault(k => string.Equals(k, newKey, StringComparison.InvariantCultureIgnoreCase)) ?? newKey;
fixedRouteValues[key] = value;
}
var query = string.Join("&", fixedRouteValues.Select(kvp => $"{kvp.Key}={kvp.Value}"));
var hrefValue = href.Value;
output.Attributes.Remove(href);
href = new TagHelperAttribute(Href, hrefValue + "?" +query);
output.Attributes.Add(href);
}
}

How to change a ClassificationFormatDefinition

My Visual Studio extension (VSIX) is derived from the Ook Language Example (found here). Basically, I have the following ClassificationFormatDefinition with a function loadSavedColor that loads the color the user has configured. Everything works fine.
[Name("some_unique_name")]
internal sealed class OokE : ClassificationFormatDefinition
{
public OokE()
{
DisplayName = "ook!"; //human readable version of the name
ForegroundColor = loadSavedColor();
}
}
Question: After the user has configured a new color, I like to invalidate the existing instance of class OokE or change the existing instances and set ForegroundColor. But whatever I do the syntax color is not updated.
I've tried:
Get a reference to class OokE and update ForegroundColor.
Invalidate the corresponding ClassificationTypeDefinition:
[Export(typeof(ClassificationTypeDefinition))]
[Name("ook!")]
internal static ClassificationTypeDefinition ookExclamation = null;
After hours of sifting through code I could create something that works. The following method UpdateFont called with colorKeyName equal to "some_unique_name" does the trick. I hope it is useful for someone.
private void UpdateFont(string colorKeyName, Color c)
{
var guid2 = Guid.Parse("{A27B4E24-A735-4d1d-B8E7-9716E1E3D8E0}");
var flags = __FCSTORAGEFLAGS.FCSF_LOADDEFAULTS | __FCSTORAGEFLAGS.FCSF_PROPAGATECHANGES;
var store = GetService(typeof(SVsFontAndColorStorage)) as IVsFontAndColorStorage;
if (store.OpenCategory(ref guid2, (uint)flags) != VSConstants.S_OK) return;
store.SetItem(colorKeyName, new[]{ new ColorableItemInfo
{
bForegroundValid = 1,
crForeground = (uint)ColorTranslator.ToWin32(c)
}});
store.CloseCategory();
}
After setting the new color, you will need to clear the cache with the following code:
IVsFontAndColorCacheManager cacheManager = this.GetService(typeof(SVsFontAndColorCacheManager)) as IVsFontAndColorCacheManager;
cacheManager.ClearAllCaches();
var guid = new Guid("00000000-0000-0000-0000-000000000000");
cacheManager.RefreshCache(ref guid);
guid = new Guid("{A27B4E24-A735-4d1d-B8E7-9716E1E3D8E0}"); // Text editor category

Variable scoping c#

I am fairly new to c# and am getting an error "Object reference not set to an instance of an object." I am creating an XML packet and sending it to an external device for control. If I put the following code on the form in a click event it works beautifully.
On the btn Click event it looks like this:
SetTestInfoResponse testDataDs = null;
TestInformation testInfo = null;
this.PopulateTestDataXml();
string stringRequestXML = string.Empty;
string stringResponseXML = string.Empty;
//Creates Request packet
stringRequestXML = XMLCommunicationPackets.SetTestInformation (testInfo, testInfo.TestID, testInfo.TestUser, testInfo.TestSampleType, testInfo.TestSampleId, testInfo.TestMethodNumber, testInfo.TestTubeSn, testInfo.TestComments);
//Write set Test Info XML Packet and get response for ack or failure.
stringResponseXML = PluginContext.GetInstance().InstrumentDriverCurrent.GetInstrumentControl().SetCommonParameter(stringRequestXML);
However, If I move my entire function out of the form and try to call it when clicking a button I get the error.
written in a method off the form in a .cs file it reads:
public static SetTestInfoResponse SetTestData()
{
SetTestInfoResponse testDataDs = null;
TestInformation testInfo = null;
string stringRequestXML = string.Empty;
string stringResponseXML = string.Empty;
//Creates Request packet
stringRequestXML = XMLCommunicationPackets.SetTestInformation (testInfo, testInfo.TestID, testInfo.TestUser, testInfo.TestSampleType, testInfo.TestSampleId, testInfo.TestMethodNumber, testInfo.TestTubeSn, testInfo.TestComments);
//Write set Test Info XML Packet and get response for ack or failure.
stringResponseXML = PluginContext.GetInstance().InstrumentDriverCurrent.GetInstrumentControl().SetCommonParameter(stringRequestXML);
The error occurs when building stringRequestXml.
Part of my problem is the PopulateTestData() is a method on the form itself. Its purpose is to take data from txtboxes and cmbboxes and assign them to their respective arguments..
private TestInformation PopulateTestDataXml()
{
TestInformation UiTestData = new TestInformation();
UiTestData.TestID = txtTestId.Text;
UiTestData.TestUser = cmbUsers.SelectedItem.ToString();
UiTestData.TestSampleType = txtSampleType.Text;
UiTestData.TestSampleId = txtSampleId.Text;
UiTestData.TestMethodNumber = Convert.ToInt32(cmbMethod.SelectedItem);
UiTestData.TestTubeSn = txtTubeSerialNum.Text;
UiTestData.TestComments = txtComments.Text;
return UiTestData;
}
Here is the SetTestInformation() method where I am getting the error:
public static string SetTestInformation(TestInformation testInfo, string stringTestId, string stringUser, string stringSampleType, string stringSampleId, int intMethodNumber, string stringTubeSn, string stringComments)
{
try
{
string stringRequestXMLPacket = string.Empty;
string stringType = #"Request";
string stringCommand = #"Set";
string stringArgument = #"TestInformation";
CommunicationPacket requestXMLPacket = new CommunicationPacket(stringRootTag, stringXMLVersion, stringType, stringCommand);
requestXMLPacket.AddCommandArgument(stringArgument);
requestXMLPacket.AddArgumentItem(stringArgument, "sTestId", testInfo.TestID.ToString());
requestXMLPacket.AddArgumentItem(stringArgument, "sUser", testInfo.TestUser.ToString());
requestXMLPacket.AddArgumentItem(stringArgument, "sSampleType", testInfo.TestSampleType.ToString());
requestXMLPacket.AddArgumentItem(stringArgument, "sSampleId", testInfo.TestSampleId.ToString());
requestXMLPacket.AddArgumentItem(stringArgument, "nMethodNumber", testInfo.TestMethodNumber.ToString());
requestXMLPacket.AddArgumentItem(stringArgument, "sTubeSn", testInfo.TestTubeSn.ToString());
requestXMLPacket.AddArgumentItem(stringArgument, "sComments", testInfo.TestComments.ToString());
stringRequestXMLPacket = requestXMLPacket.CreateXMLPacket();
return stringRequestXMLPacket;
}
catch (Exception ex)
{
throw ex;
}
}
Iknow I am having trouble with the variable scope here. I still have to use the method PopulateTestDataXml on the form before I call the setTestData() method. But when I call the Method I have to declare testInfo = null or the parameters for SetTestInformation are not valid ("Does not exist in the current context"). What would I need to pass and how for this to work as a called method on the form btn click? I need to do this as I have alot of deserializing functions written as well to catch error messages in the response xml (these all work fine) and its just too much info on the click event. (And I need to learn).
Thanks
Neither of your examples should work (regardless of where you put them). This is simply incorrect:
TestInformation testInfo = null;
// ...
stringRequestXML = XMLCommunicationPackets.SetTestInformation (testInfo,
testInfo.TestID, ...);
// ^^ BANG!
Your testInfo object is null. When you try and access anything on a null object.. a NullReferenceException is thrown. You need to initialize it first. You're trying to do that in your PopulateTestDataXml method.. which returns the object your after. So change your code to this:
TestInformation testInfo = PopulateTestDataXml(); // assign it
Here is your problem..
public static SetTestInfoResponse SetTestData()
{
SetTestInfoResponse testDataDs = null;
TestInformation testInfo = null;
string stringRequestXML = string.Empty;
string stringResponseXML = string.Empty;
//Creates Request packet
stringRequestXML = XMLCommunicationPackets.SetTestInformation (testInfo, testInfo.TestID, testInfo.TestUser, testInfo.TestSampleType, testInfo.TestSampleId, testInfo.TestMethodNumber, testInfo.TestTubeSn, testInfo.TestComments);
//Write set Test Info XML Packet and get response for ack or failure.
stringResponseXML = PluginContext.GetInstance().InstrumentDriverCurrent.GetInstrumentControl().SetCommonParameter(stringRequestXML);
Are you assigning values for these objects I see they are just declared but never assigned.
SetTestInfoResponse testDataDs = null;
TestInformation testInfo = null;
i don't see you use null objects, so i'm wonder if you set them later, also u said the error happen on
private TestInformation PopulateTestDataXml()
{
TestInformation UiTestData = new TestInformation();
UiTestData.TestID = txtTestId.Text;
UiTestData.TestUser = cmbUsers.SelectedItem.ToString();
UiTestData.TestSampleType = txtSampleType.Text;
UiTestData.TestSampleId = txtSampleId.Text;
UiTestData.TestMethodNumber = Convert.ToInt32(cmbMethod.SelectedItem);
UiTestData.TestTubeSn = txtTubeSerialNum.Text;
UiTestData.TestComments = txtComments.Text;
return UiTestData;
}
after moving it out of your form, which mean possibly it's text box references is broken...
so what you can do, is store a pointer, like in your program.cs where you call your form to show up,
you can create an static object of form, and then put it in your class, then set it in program.cs file like :
Form1 f=new Form();
MyClass.staticFormPointer = f;
and also replace (new Form()), with (f) on the calling method,
your my class is like this:
class MyClass{
public static Form1 staticFormPointer = null;
//your code
.
.
.
// and in your methods you call it like this txtBox1.Text -> staticFormPointer.txtBox1.Text
}

How To add another constructor with parameter in linq class(Table)

I am using LINQ to SQL in an ASP.NET project. While inserting the table I need to convert the values to the particular table object and I need to insert.
For that I created a new constructor in that table with parameter so that I can assign my value to that table object , the assign the functionality is working but while inserting (obj.TS_Questions.InsertOnSubmit(mytableobject);) I get null exception.
my code::
default constructor for my table
public TS_Question()
{
this._TS_Options = new EntitySet<TS_Option>(new Action<TS_Option>(this.attach_TS_Options), new Action<TS_Option>(this.detach_TS_Options));
this._TS_QuestGroups = new EntitySet<TS_QuestGroup>(new Action<TS_QuestGroup>(this.attach_TS_QuestGroups), new Action<TS_QuestGroup>(this.detach_TS_QuestGroups));
this._TS_QuestRecords = new EntitySet<TS_QuestRecord>(new Action<TS_QuestRecord>(this.attach_TS_QuestRecords), new Action<TS_QuestRecord>(this.detach_TS_QuestRecords));
this._TS_Admin = default(EntityRef<TS_Admin>);
this._TS_LevelType = default(EntityRef<TS_LevelType>);
this._TS_OptionTypeLT = default(EntityRef<TS_OptionTypeLT>);
OnCreated();
}
constructor created by me
public TS_Question(Guid Quest_QuestIDBL, string Quest_NameBL, Nullable<Guid> Quest_OptionTypeIDBL, Guid Quest_AdminIDBL, Guid Ques_LevelIDBL, int Quest_TimeBL, int Quest_MarkBL, string Qest_ExplanationBL, Nullable<bool> Qest_IsMultipleAnswerBL)
{
this._TS_Options = new EntitySet<TS_Option>(new Action<TS_Option>(this.attach_TS_Options), new Action<TS_Option>(this.detach_TS_Options));
this._TS_QuestGroups = new EntitySet<TS_QuestGroup>(new Action<TS_QuestGroup>(this.attach_TS_QuestGroups), new Action<TS_QuestGroup>(this.detach_TS_QuestGroups));
this._TS_QuestRecords = new EntitySet<TS_QuestRecord>(new Action<TS_QuestRecord>(this.attach_TS_QuestRecords), new Action<TS_QuestRecord>(this.detach_TS_QuestRecords));
this._TS_Admin = default(EntityRef<TS_Admin>);
this._TS_LevelType = default(EntityRef<TS_LevelType>);
this._TS_OptionTypeLT = default(EntityRef<TS_OptionTypeLT>);
OnCreated();
this._Quest_QuestID = Quest_QuestIDBL;
this._Quest_Name = Quest_NameBL;
if (Quest_OptionTypeIDBL != null)
{
this._Quest_OptionTypeID = Quest_OptionTypeIDBL;
}
this._Quest_AdminID = Quest_AdminIDBL;
this._Ques_LevelID = Ques_LevelIDBL;
this._Quest_Time = Quest_TimeBL;
this._Quest_Mark = Quest_MarkBL;
this._Qest_Explanation = Qest_ExplanationBL;
this._Qest_IsMultipleAnswer = Qest_IsMultipleAnswerBL;
}
Please help me out from this problem
Honestly, I haven't looked too deep, but it looks like that OnCreated is sitting a little far north... You probably want to call it after you're done setting up your variables. Other than that i'd say make sure you're properly initializing everything in the method calling the constructor.
You can call default constructor like this, it works fine for me:
public partial class MyClass
{
public MyClass(string fieldValue1,int fieldValue2)
: this()
{
this.field1= fieldValue1;
this.field2 = fieldValue2;
}
}
If this do the trick, you can read more about using contructors in C# here.

Categories