The controls on my WebPart are not being created because the condition:
if (this.dpsvisWebPart != null && this.dpsvisWebPart.CustomTitleProp != null)
...fails due to CustomTitleProp being null. Yet it is declared in the WebPart's constructor and should not be null.
Here is the code:
namespace DirectPaymentSectionsWebPart.DPSVisualWebPart
{
[ToolboxItemAttribute(false)]
public class DPSVisualWebPart : WebPart
{
// Text
[WebBrowsable(true),
Category("Financial Affairs Forms"),
Personalizable(PersonalizationScope.Shared),
WebDisplayName("WebPart Title Text")]
public string CustomTitleProp { get; set; }
// Checkboxes
[WebBrowsable(true),
Category("Financial Affairs Forms"),
Personalizable(PersonalizationScope.Shared),
WebDisplayName("Generate Section1")]
public bool CheckboxGenSection1 { get; set; }
. . .
// Visual Studio might automatically update this path when you change the Visual Web Part project item.
private const string _ascxPath = #"~/_CONTROLTEMPLATES/DirectPaymentSectionsWebPart/DPSVisualWebPart/DPSVisualWebPartUserControl.ascx";
. . .
protected override void CreateChildControls()
{
//base.CreateChildControls(); // added this 5/28/2015 <= commented out, because it is being called over and over again
DPSVisualWebPartUserControl control = Page.LoadControl(_ascxPath) as DPSVisualWebPartUserControl;
//DPSVisualWebPartUserControl control = Page.LoadControl(siteUrl) as DPSVisualWebPartUserControl;
if (control != null)
{
control.dpsvisWebPart = this;
}
Controls.Add(control);
}
} // class DPSVisualWebPart
So why might it be that CustomTitleProp is null at the previously noted juncture? Here that code is with more context:
public partial class DPSVisualWebPartUserControl : UserControl
{
public DPSVisualWebPart dpsvisWebPart { get; set; }
System.Web.UI.ScriptManager scriptMgr;
. . .
protected void Page_Load(object sender, EventArgs e)
{
base.OnPreRender(e);
if (System.Web.UI.ScriptManager.GetCurrent(this.Page) == null)
{
scriptMgr = new System.Web.UI.ScriptManager();
scriptMgr.EnablePartialRendering = true;
this.Controls.AddAt(0, scriptMgr);
}
if (this.dpsvisWebPart != null && this.dpsvisWebPart.CustomTitleProp != null)
{
lbl_Title.Text = String.Format("<h1>{0}</h1>", this.dpsvisWebPart.CustomTitleProp.ToString());
. . .
UPDATE
Under the heading of "Adventures in Folder Diffing" comes this:
The legacy project contains a file named FileListAbsolute.txt with this content:
C:\Projects\DirectPaymentSectionsWebPart\DirectPaymentSectionsWebPart\bin\Debug\DirectPaymentSectionsWebPart.dll
C:\Projects\DirectPaymentSectionsWebPart\DirectPaymentSectionsWebPart\bin\Debug\DirectPaymentSectionsWebPart.pdb
C:\Projects\DirectPaymentSectionsWebPart\DirectPaymentSectionsWebPart\bin\Debug\Microsoft.Sharepoint.Sandbox.dll
C:\Projects\DirectPaymentSectionsWebPart\DirectPaymentSectionsWebPart\obj\Debug\ResolveAssemblyReference.cache
C:\Projects\DirectPaymentSectionsWebPart\DirectPaymentSectionsWebPart\obj\Debug\DirectPaymentSectionsWebPart.dll
C:\Projects\DirectPaymentSectionsWebPart\DirectPaymentSectionsWebPart\obj\Debug\DirectPaymentSectionsWebPart.pdb
The new project contains a file of the same name with this content:
C:\Projects\DirectPaymentSectionsWebPart\DirectPaymentSectionsWebPart\bin\Debug\DirectPaymentSectionsWebPart.dll
C:\Projects\DirectPaymentSectionsWebPart\DirectPaymentSectionsWebPart\bin\Debug\DirectPaymentSectionsWebPart.pdb
C:\Projects\DirectPaymentSectionsWebPart\DirectPaymentSectionsWebPart\bin\Debug\Microsoft.Sharepoint.Sandbox.dll
C:\Projects\DirectPaymentSectionsWebPart\DirectPaymentSectionsWebPart\obj\Debug\ResolveAssemblyReference.cache
C:\Projects\DirectPaymentSectionsWebPart\DirectPaymentSectionsWebPart\obj\Debug\DirectPaymentSectionsWebPart.dll
C:\Projects\DirectPaymentSectionsWebPart\DirectPaymentSectionsWebPart\obj\Debug\DirectPaymentSectionsWebPart.pdb
C:\Projects\DirectPaymentWebForm\DirectPaymentSectionsWebPart\obj\Debug\ResolveAssemblyReference.cache
C:\Projects\DirectPaymentWebForm\DirectPaymentSectionsWebPart\obj\Debug\DirectPaymentSectionsWebPart.dll
C:\Projects\DirectPaymentWebForm\DirectPaymentSectionsWebPart\bin\Debug\DirectPaymentSectionsWebPart.dll
C:\Projects\DirectPaymentWebForm\DirectPaymentSectionsWebPart\bin\Debug\DirectPaymentSectionsWebPart.pdb
C:\Projects\DirectPaymentWebForm\DirectPaymentSectionsWebPart\bin\Debug\Microsoft.Sharepoint.Sandbox.dll
C:\Projects\DirectPaymentWebForm\DirectPaymentSectionsWebPart\obj\Debug\DirectPaymentSectionsWebPart.pdb
So I wonder: should I remove the first six entries from the new project's file, which reference the legacy project? Or will doing so cause Pearl Harbor III to erupt?
UPDATE 2
I tried this:
...and it turns out that there already is a ScriptManager by this point (Page_Load()) event, and that it already has EnablePartialRendering set, and so this code is moot. The question still is, though, why in Hec Ramsay is CustomTitle null here:
if (this.dpsvisWebPart != null && this.dpsvisWebPart.CustomTitleProp != null)
...which comes right after the (about-to-be-removed-because-its-moot) code in the Page_Load() event?
UPDATE 3
Alright (or is it "all right"?) - which is, at any rate, a funny thing to say when obviously not everything is all right, but then again, it's Friday, so it's okay...anyway:
I wondered: "maybe 'CustomTitleProp' is null because the Web Editor (after all, that's where CustomTitleProp lives) is not being created/rendered. And sure enough, when I went to "Edit Web Part" the Web Part Editor wouldn't even display, and I again got blasted with the red-hot, reeking-breath Sharepoint mother-in-law thus:
"Web Part Error: A Web Part or Web Form Control on this Page cannot be displayed or imported. The type DirectPaymentSectionsWebPart.DPSVisualWebPart.DPSVisualWebPart, DirectPaymentSectionsWebPart, Version=1.0.0.0, Culture=neutral, PublicKeyToken=bbf47e850237632c could not be found or it is not registered as safe."
Alas and anon, it is back to the coding board again! For forsooth, why is my WebPartEditor not displaying?
(sorry, I've been reading "A Connecticut Yankee in King Arthur's Court" of late).
I think you have to just register your dll as safe in Web.config.
Once I entered a value in the Web Part Editor for this, the problem went away. But the question still remains, how to prevent this prior to adding a value via the Web Part Editor? I see no way to give this a default value; I assume even a space (" ") would do the trick...
Could I do something like:
[WebBrowsable(true),
Category("Financial Affairs Forms"),
Personalizable(PersonalizationScope.Shared),
WebDisplayName("WebPart Title Text")]
public string CustomTitleProp { call a custom method to return a space or something; set; }
?
Related
I have a custom control. It has an image. I have exposed the ImageURL attribute in the custom control code by creating a new attribute called ButtonIconImgSrc as follows:
[Category("Appearance")]
[Description("Gets or sets the logo image path")]
public String ButtonIconImgSrc
{
get
{
EnsureChildControls();
return iconImg.ImageUrl;
}
set
{
if (value != null)
{
iconImg.ImageUrl = value.ToString();
}
}
}
I compile the customeControl code to create a dll and then add the dll to my web site solution so i can drag and drop it onto my designer view or dynamically create it. Everything seems to work great in designer, i drop it on, set my custom atributes and looks good.
..... but the img does not show when i compile and run the site in a browser. nothing gets set correctly, its all lost by the time it gets back to the calling code - labels and textboxes and widths and heights etc. I want to create this customcontrol dynamically, not use the designer but same issue.
Below is the code that calls the above 'set' method, except after it comes back from th eset method its still blank.
protected void Page_Load(object sender, EventArgs e)
{
myCustomButton tb = new myCustomButton();
tb.ButtonIconImgSrc = "~/imgs/target_logo.png";
pnlButtons.Controls.Add(tb);
}
I see the code above being hit and the string "~/imgs/ibc_foh.png" being set in the myCustomButton code and that code exits and everything looks good. When the debugger gets back to the calling class (my websites Page_Load) the attribute tb.ButtonIconImgSrc is still blank, "". And so the image does not appear.
Updated: problem solved. I misunderstood the lifecycle of the control, the image was being overwritten in the createChildControls method
Create/Add a Generic HttpHandler page to your project.
in the function 'ProcessRequest'. there will be a HttpContext object (called context).
do as followed:
public class YouHandlerPage : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
// REVIEW AND PROCESS THE REQUEST (i.e. ...
// context.Request.QueryString
// context.Request.RequestContext.RouteData.Values;
// context.Request.Form
string fDirectory = #"C:\Users\john\Desktop\";
string fileName = "ibc";
string fileExt = "png";
context.Response.StatusCode = 200;
context.Response.ContentType = "Image/" + fileExt;
//let context.Response.ContentLength be specified by the following WriteFile method
context.Response.WriteFile(Format.String("{0}{1}.{2}", fDirectory, fileName, fileExt));
}
public bool IsReusable { get { return false;} }
}
now, run your web application.. and goto localhost:<portassigned>/<handlerpagefilename>.ashx
Where locahost:<portassigned> is your domain (or IIS Express assigned), and <handlerpagefilename> is whatever your named you added GenericHandlerPage (which should end with .ashx).
When you visit this page, you should get your image..
Further Review
review Registering Routes to map to your HandlerPage.
review HttpModules as an alternative to httphandler pages
problem solved. I misunderstood the lifecycle of the control, the image was being overwritten in the createChildControls method
I followed the https://github.com/jamesmontemagno/Xam.NavDrawer example and Im able to successfully use the drawer layout with fragments(infact nested fragments with view pager). I have one issue, when I click the back button the navigation drawer menu item on the left side is not synced with the fragment that is shown.
This is how I navigate to other fragments
SupportFragmentManager.BeginTransaction().Replace(Resource.Id.content, fragment).AddToBackStack(fragment.Name).Commit();
I tried the OnAttachFragment method, but its not called on back stack. I also tried the SupportFragmentManager BackStackChanged method, but I could not get the current fragment that is in the view to update the navigation drawer menu title.
I had the same issue and couldn't find any solution as well. Although this question is kinda old, my solution may help someone. I'm not sure if it's the best solution but it works for me.
So first you need to add variable to store ID of previously checked item:
private int previousItemChecked;
set it initially to your default checked item:
if (savedInstanceState == null) {
selectItem(0);
previousItemChecked = 0;
}
then edit the fragment transaction so that the transaction title in backstack contains position of the previously checked item converted to string and after the transaction is done set the variable previousItemChecked to the currently checked item id:
fragmentManager.beginTransaction().replace(R.id.content_frame, selectedFragment).addToBackStack(""+previousItemChecked).commit();
previousItemChecked = mDrawerList.getCheckedItemPosition();
and finally in method onBackPressed you need to get the string previously assigned to fragment transaction, parse it to int and update the drawer according to the obtained id:
#Override
public void onBackPressed() {
if(fragmentManager.getBackStackEntryCount() > 0) {
String title = fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount()-1).getName();
int pos = Integer.parseInt(title);
previousItemChecked = pos;
mDrawerList.setItemChecked(pos, true);
}
super.onBackPressed();
}
I took the code from my app created in Android Studio so it isn't for Xamarin but if you update the code it should work with it too. What's important here is the idea how it's done. I hope the answer is understandable and will help someone.
I had the same issue and I solved like this:
Inside selectItem we are passing the position Item;
So if position is 0 (or whatever is fragment we want it appears as first indipendently from it's position on the menu) we have to avoid to save the first transaction. So...
private void selectItem(position){
//...
if (position != 0)
{
SupportFragmentManager.BeginTransaction()
.Replace(Resource.Id.content_frame, fragment)
.AddToBackStack(fragment.Name)
.Commit();
}
else
{
SupportFragmentManager.BeginTransaction()
.Replace(Resource.Id.content_frame, fragment)
.Commit();
}
}
Managed to achieve this by injecting a DestinationChangedListener into the NavController like this:
NavController navController.addOnDestinationChangedListener(this);
and then:
#Override
public void onDestinationChanged(#NonNull NavController controller,
#NonNull NavDestination destination,
#Nullable Bundle arguments) {
NavigationView navigationView = findViewById(R.id.nav_view);
if(navigationView != null){
navigationView.setCheckedItem(destination.getId());
}
}
Hi i have code that create new variable for textbox that not exist yet, but can be created on runtime. it work great, see code bellow
public void btnApagar_Click(object sender, EventArgs e)
{
TextBox txtAcessorio4 = (TextBox)gpbCategoria.Controls.Find("txtAcessorio4", false).FirstOrDefault();
if (txtAcessorio4 != null && txtAcessorio4.Text == "" && lblAcessorio4.Name == "lblAcessorio4")
{
MessageBox.Show("Perfect");
}
}
problem that i would like to use this created variable on another places in code too, i i tried:
public partial class cad_produto_acessorios_novo : Form
{
TextBox txtAcessorio4 = (TextBox)gpbCategoria.Controls.Find("txtAcessorio4", false).FirstOrDefault();
}
public void btnApagar_Click(object sender, EventArgs e)
{
if (txtAcessorio4 != null && txtAcessorio4.Text == "" && lblAcessorio4.Name == "lblAcessorio4")
{
MessageBox.Show("Perfect");
}
}
but I had bellow error on public partial class(gpbCategoria is my groupbox name):
Error 1 A field initializer cannot reference the non-static field, method, or property 'InfoEarth_Cad_Cliente.cad_produto_acessorios_novo.gpbCategoria
Somebody know how to solve it?
Many of your recent questions go into the same direction.
If you want to access a control (like a label or a textbox) you have created at runtime you need some kind of container (an array or a list). This way the .net framework checks during runtime if the control is present in the container.
void BtnApagar_ClickClick(object sender, EventArgs e)
{
// test if textbox 4 exist by counting the number of added textboxes
if(textBoxList.Count ==4 || textBoxList.Count > 4)
{
// List and array are 0 based --> index 3 is the 4th textbox
MessageBox.Show("Perfect we have "
+ " at least 4 boxes and the name is: "
+ textBoxList[3].Name);
}else {
MessageBox.Show("Number of textboxes is not enough - add more");
}
}
Instead of using (TextBox)gpbCategoria.Controls.Find("txtAcessorio4", false).FirstOrDefault();
we can access the list by index to get a certain "future" instance for textbox_4
You may take a look at my example project and play around with it. It can be openend with sharpdevelop 4.3.
I am trying to get a StringElement's 'Value' to update in the UI when I set it after already setting up the DVC.
e.g:
public partial class TestDialog : DialogViewController
{
public TestDialog() : base (UITableViewStyle.Grouped, null)
{
var stringElement = new StringElement("Hola");
stringElement.Value = "0 Taps";
int tapCount = 0;
stringElement.Tapped += () => stringElement.Value = ++tapCount + " Taps";
Root = new RootElement("TestDialog")
{
new Section("First Section")
{
stringElement,
},
};
}
}
However the StringElement.Value is just a public field, and is only written to the UICell during initialization when Element.GetCell is called.
Why isn't it a property, with logic in the setter to update the UICell (like the majority of Elements, e.g. EntryElement.Value):
public string Value
{
get { return val; }
set
{
val = value;
if (entry != null)
entry.Text = value;
}
}
EDIT :
I made my own version of StringElement, derived from Element (basically just copied the source code from here verbatim)
I then changed it to take a class scoped reference to the cell created in GetCell, rather than function scoped. Then changed the Value field to a property:
public string Value
{
get { return val; }
set
{
val = value;
if (cell != null)
{
// (The below is copied direct from GetCell)
// The check is needed because the cell might have been recycled.
if (cell.DetailTextLabel != null)
cell.DetailTextLabel.Text = Value == null ? "" : Value;
}
}
}
It works in initial testing. However I am not sure on whether taking a reference to the cell is allowed, none of the other elements seem to do it (they only take references to control's placed within the cells). Is it possible that multiple 'live'* cell's are created based on the one MonoTouch.Dialog.Element instance?
*I say live to indicate cells currently part of the active UI. I did notice when navigating back to the dialog from a child dialog the GetCell method is invoked again and a new cell created based on the Element, but this is still a 1-1 between the element and the live cell.
For the main question:
Why does MonoTouch.Dialog use public fields for some Element options, and public properties for others?
I've been through the code, and I don't think there's a consistent reason for use of either.
The Dialog project was not part of the MonoTouch project initially - I don't think Miguel knew how useful it was going to turn out when he started wrote and grew it - I think he was more focussed on writing other apps like TweetStation at the time.
I know of several people (including me!) who have branched the code and adapted it for their purposes. I would guess at some future point Xamarin might write a 2.0 version with stricter coding standards.
Taking references to live cells
For limited use you can do this... but in general don't.
The idea of the table view is that cells get reused when the user scrolls up and down - especially in order to save memory and ui resources. Because of this is a long list, multiple elements might get references to the same cell.
If you do want to cache a cell reference then you probably should override GetCell() so that it never tries to reuse existing cells (never calls DequeueReusableCell)
Alternatively, you could try to change some code in the base Element class in order to find out if the Element has a current attached cell - this is what CurrentAttachedCell does in my branch of Dialog https://github.com/slodge/MvvmCross/blob/master/Cirrious/Cirrious.MvvmCross.Dialog/Dialog/Elements/Element.cs (but that branch has other added functions and dependencies so you probably won't want to use it for this current work!)
Trying to work out this whole web part personalisation, and trying to implement it for a list box.
Well the end result will be two list boxes, with interchangeable values (ie, a value will only exist in one of the listboxes)
But I can't maintain the datasource for it. So maybe I'm going about it wrong?
This is what I have for a test H2 tag on the page
[Personalizable(PersonalizationScope.User)]
public string LabelText {
get { return h2Test.InnerText; }
set { h2Test.InnerText = value; }
}
And it works fine, if I have a textbox and use it to change the value of LabelText, then when I close the browser it automagically persists the change.
So I thought, ok, then maybe the same will work with a list box
[Personalizable(PersonalizationScope.User)]
public DomainList Domains {
get { return (DomainList)lstBxDomains.DataSource; }
set {
lstBxDomains.DataSource = value;
lstBxDomains.DataBind();
}
}
Where DomainList is just a class which extends List, and Domain is just a three field class, int, string, string.
But it doesn't, so is this too complicated for the webpart personalisation automagican, or have i just implement it wrongly (Which is more than likely)
This is my event handler to remove the items from the list:
protected void btnRemDomain_Click(object sender, EventArgs e) {
if (IsPostBack && lstBxDomains.SelectedIndex > -1) {
for (int i = 0; i < lstBxDomains.Items.Count; i++) {
if (lstBxDomains.Items[i].Selected) {
Domains.Remove(Domains.Find(d => d.ID.ToString() == lstBxDomains.Items[i].Value));
}
}
Domains = Domains;
}
}
The Domains=Domains; line is in there to see if explicitly setting the value made a difference (as Removing doesn't acutally reset the value of the field), but it doesn't. I've also tried creating a new local DomainList setting it to the global one, and then doing the remove/find on it, and then setting the local one to the global. But not working either.
I have managed to resolve this by using WebPart.SetPersonalizationDirty(this); in the set accessor of Domains, but would someone mind confirming if this is an appropriate way to do it?