I've just made my first WebControl, but I'm having some troubles.
Here's a sample of what I have so far:
public class NotificationPopup : WebControl
{
public bool? IsAccepted { get; set; }
public void Show()
{
Panel root = new Panel();
Button b1 = new Button();
b1.Text = "Ok";
b1.Click += delegate
{
IsAccepted = true;
};
Button b2 = new Button();
b2.Text = "Cancel";
b2.Click += delegate
{
IsAccepted = false;
};
Controls.Add(root);
}
}
When I call Show the panel is displayed, but when I press the button the IsAccepted property is never changed. Can anyone tell me what I'm doing wrong?
Do you re-create your buttons by calling Show again ? If you don't, the buttons are not created and the event handlers will not fire.
Related
I use Reflection to set the Label.TextProperty.CoerceValue to my custom delegate (TextProperty.CoerceValue are null by default)
but when Label text changed, the delegate are not called
the same strategy are apply/tried on Image.SourceProperty, Entry.TextProperty
all are called successful
is bug or Label.TextProperty by design will not call CoerceValue delegate?
thank you very much.
Xamarin.Forms 4.3.0.947036
var property = Label.TextProperty;
var coerceValue = property.GetType().GetProperty("CoerceValue", BindingFlags.NonPublic | BindingFlags.Instance);
oldDelegate = coerceValue?.GetValue(property) as BindableProperty.CoerceValueDelegate;
coerceValue?.SetValue(property, (bindable, value) => {
var modified = ModifyValue(value); // simply modify the value if required
return modified
});
If you want to call CoerceValue when Label.Text changed, I suggest you can use Bindable Properties to bind Label.TextPrperty.
public partial class Page9 : ContentPage
{
public static readonly BindableProperty labelvalueProperty = BindableProperty.Create("labelvalue", typeof(string), typeof(Page9), null , coerceValue: CoerceValue);
public string labelvalue
{
get { return (string)GetValue(labelvalueProperty); }
set { SetValue(labelvalueProperty, value); }
}
private static object CoerceValue(BindableObject bindable, object value)
{
string str = (string)value;
if(str=="cherry")
{
str = "hello world!";
}
return str;
}
public Page9 ()
{
InitializeComponent ();
label1.SetBinding(Label.TextProperty, "labelvalue");
labelvalue = "this is test";
BindingContext = this;
}
private void Btn1_Clicked(object sender, EventArgs e)
{
labelvalue = "cherry";
}
}
You can see the CoerceValue can be fired when Label.Text property changed.
I created a new Page Page1 in a Xamarin.Forms Project, with the following simple code in the code behind:
public Page1()
{
InitializeComponent();
}
protected override void OnAppearing()
{
Label l = new Label();
BindableProperty.CoerceValueDelegate d = (s, a) =>
{
string modified = "textY"; // simply modify the value if required
return modified;
};
var property = Label.TextProperty;
var coerceValue = property.GetType().GetProperty("CoerceValue", BindingFlags.NonPublic | BindingFlags.Instance);
var oldDelegate = coerceValue?.GetValue(property) as BindableProperty.CoerceValueDelegate;
coerceValue?.SetValue(property, d);
l.Text = "1"; // Text property is set to textY thanks to CoerceValueDelegate!
base.OnAppearing();
}
when i call l.Text = "1" the BindableProperty.CoerceValueDelegate i defined is correctly called, and l.Text is set to textY as expected.
#codetale, are you able to run this code on your side?
Why would the following code not work? I am creating a control, adding a child control and attempting to retrieve it by id using the .FindControl method.
[Test]
public void TryToFindControl()
{
var myPanel = new Panel();
var textField = new TextBox
{
ID = "mycontrol"
};
myPanel.Controls.Add(textField);
var foundControl = myPanel.FindControl("mycontrol");
// this fails
Assert.IsNotNull(foundControl);
}
Panel has not been added to Page yet, so you cannot use FindControl. Instead, you need to find it inside Panel.Controls
[TestMethod]
public void TryToFindControl()
{
var myPanel = new Panel();
var textField = new TextBox
{
ID = "mycontrol"
};
myPanel.Controls.Add(textField);
var foundControl = myPanel.Controls
.OfType<TextBox>()
.FirstOrDefault(x => x.ID == "mycontrol");
Assert.IsNotNull(foundControl);
}
Testing with Page
FindControl works only if container is added to Page.
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
var myPanel = new Panel();
var textField = new TextBox
{
ID = "mycontrol"
};
myPanel.Controls.Add(textField);
Controls.Add(myPanel);
// foundControl is not null anymore!
var foundControl = myPanel.FindControl("mycontrol");
}
}
The control must be part of the server side Page control collection hierarchy to be found.
public void TryToFindControl()
{
var myPanel = new Panel();
// key line here
Page.Controls.Add(myPanel);
var textField = new TextBox
{
ID = "mycontrol"
};
myPanel.Controls.Add(textField);
var foundControl = myPanel.FindControl("mycontrol");
Assert.IsNotNull(foundControl);
}
First I'll start form the fact I don't know of System.UI.Control, Rather System.Web.UI.Control
Then I could not find TextField Control so I used Web TextBox instead. Please adjust your code as necessary. I also used VS Test attributes
[TestMethod()]
public void TryToFindControl()
{
var editContainer = new HtmlTableCell();
editContainer.Controls.Add(new TextBox
{
ID = "mycontrol",
});
System.Web.UI.Control foundControl = null;
foreach (System.Web.UI.Control ctrl in editContainer.Controls)
{
if (ctrl.ID == "mycontrol")
{
foundControl = ctrl;
break;
}
}
// This works
Assert.IsNotNull(foundControl);
}
Based on your exact wording, if you want to access the control you added, create an instance first as variable, so you can access it directly. Please keep in mind that I don't know what you are trying to achieve globally, so my answer(s) may not apply because of that, or there maybe be better solution.
[TestMethod()]
public void TryToFindControl()
{
var editContainer = new HtmlTableCell();
var foundControl = new TextBox
{
ID = "mycontrol"
};
editContainer.Controls.Add(foundControl);
// This works
Assert.IsNotNull(foundControl);
}
I'm trying to write a webpart that basically pulls data from a list and displays it to the user. There is a feature news list where one of the columns holds a URL to an image. The web part should get the 3 most recent feature news items and create three image controls on the page. These image controls can be scrolled through by clicking on the buttons 1,2,3. (Ie, clicking on 2 will set the Visible property of image 1 and image 3 to false).
I have managed to implement AJAX here, but am now trying to use the UpdatePanelAnimationExtender from the AJAX Control Toolkit.
I have followed all instructions on how to use the toolkit, add it to the GAC, add a safe assembly, etc, and have gotten past all the errors besides this one:
"Page cannot be null. Please ensure that this operation is being performed in the context of an ASP.NET request"
My complete code below:
using System; using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.WebControls;
using System.Web.Extensions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using System.ComponentModel;
using AjaxControlToolkit;
namespace FeatureNewsWebpartFeature {
[Guid("7ad4b959-d494-4e85-b164-4e4231692b8b")]
public class FeatureNewsWebPart : Microsoft.SharePoint.WebPartPages.WebPart
{
private bool _error = false;
private string _listName = null;
private string _imageColumn = null;
Image image1;
Image image2;
Image image3;
UpdatePanelAnimationExtender upAnimator;
[Personalizable(PersonalizationScope.Shared)]
[WebBrowsable(true)]
[System.ComponentModel.Category("List Connection Settings")]
[WebDisplayName("List Name")]
[WebDescription("Enter the name of the news list")]
public string ListName
{
get
{
if (_listName == null)
{
_listName = "News";
}
return _listName;
}
set { _listName = value; }
}
[Personalizable(PersonalizationScope.Shared)]
[WebBrowsable(true)]
[System.ComponentModel.Category("List Connection Settings")]
[WebDisplayName("Image Column Name")]
[WebDescription("Enter the column name of the ArtfulBits Image Upload column")]
public string ImageUrlColumn
{
get
{
if (_imageColumn == null)
{
_imageColumn = "Feature Image";
}
return _imageColumn;
}
set { _imageColumn = value; }
}
public FeatureNewsWebPart()
{
this.ExportMode = WebPartExportMode.All;
}
/// <summary>
/// Create all your controls here for rendering.
/// Try to avoid using the RenderWebPart() method.
/// </summary>
protected override void CreateChildControls()
{
if (!_error)
{
try
{
base.CreateChildControls();
//Create script manager
if (ToolkitScriptManager.GetCurrent(this.Page) == null)
{
ToolkitScriptManager scriptHandler = new ToolkitScriptManager();
scriptHandler.ID = "scriptHandler";
scriptHandler.EnablePartialRendering = true;
this.Controls.Add(scriptHandler);
}
//Create update panel
System.Web.UI.UpdatePanel imageUpdatePanel = new System.Web.UI.UpdatePanel();
imageUpdatePanel.ID = "imageUpdatePanel";
imageUpdatePanel.UpdateMode = UpdatePanelUpdateMode.Conditional;
this.Controls.Add(new LiteralControl("<div id=\"updateContainer\">"));
this.Controls.Add(imageUpdatePanel);
this.Controls.Add(new LiteralControl("</div>"));
//Make SPSite object and retrieve the three most recent feature news items
SPSite site = SPContext.Current.Site;
using (SPWeb web = site.OpenWeb())
{
SPList oList = web.Lists[ListName];
SPQuery oQuery = new SPQuery();
oQuery.RowLimit = 3;
oQuery.Query = "<OrderBy>" +
"<FieldRef Name='Modified' Ascending='False' /></OrderBy>" +
"<Where>" +
"<Eq>" +
"<FieldRef Name='ContentType' />" +
"<Value Type='Choice'>Feature News Item</Value>" +
"</Eq>" +
"</Where>";
oQuery.ViewFields = string.Concat(
"<FieldRef Name='Feature_x0020_Image' />" +
"<FieldRef Name='Feature_x0020_Order' />");
image1 = new Image();
image2 = new Image();
image3 = new Image();
//For each item, extract image URL and assign to image object
SPListItemCollection items = oList.GetItems(oQuery);
foreach (SPListItem oListItem in items)
{
string url = oListItem["Feature_x0020_Image"].ToString();
url = url.Substring(url.IndexOf("/Lists"));
url = url.Remove(url.IndexOf(";#"));
switch (oListItem["Feature_x0020_Order"].ToString())
{
case "1":
image1.ImageUrl = url;
break;
case "2":
image2.ImageUrl = url;
break;
case "3":
image3.ImageUrl = url;
break;
default:
//ERROR
break;
}
}
if (!(Page.IsPostBack))
{
image1.Visible = true;
image2.Visible = false;
image3.Visible = false;
}
imageUpdatePanel.ContentTemplateContainer.Controls.Add(image1);
imageUpdatePanel.ContentTemplateContainer.Controls.Add(image2);
imageUpdatePanel.ContentTemplateContainer.Controls.Add(image3);
//Create animation for update panel
upAnimator = new UpdatePanelAnimationExtender();
upAnimator.ID = "upAnimator";
upAnimator.TargetControlID = imageUpdatePanel.ID;
const string xml = "<OnUpdating>" +
"<Parallel duration=\".25\" Fps=\"30\">" +
"<FadeOut AnimationTarget=\"updateContainer\" minimumOpacity=\".2\" />" +
"</OnUpdating>" +
"<OnUpdated>" +
"<FadeIn AnimationTarget=\"updateContainer\" minimumOpacity=\".2\" />" +
"</OnUpdated>";
Animation.Parse(xml, upAnimator);
this.Controls.Add(upAnimator);
Button b1 = new Button();
b1.ID = "b1i";
b1.Click += new EventHandler(b1_Click);
b1.Text = "Image 1";
Button b2 = new Button();
b2.ID = "b2i";
b2.Click += new EventHandler(b2_Click);
b2.Text = "Image 2";
Button b3 = new Button();
b3.ID = "b3i";
b3.Click += new EventHandler(b3_Click);
b3.Text = "Image 3";
this.Controls.Add(b1);
this.Controls.Add(b2);
this.Controls.Add(b3);
AsyncPostBackTrigger tr1 = new AsyncPostBackTrigger();
tr1.ControlID = b1.ID;
//tr1.EventName = "Click";
imageUpdatePanel.Triggers.Add(tr1);
AsyncPostBackTrigger tr2 = new AsyncPostBackTrigger();
tr2.ControlID = b2.ID;
//tr2.EventName = "Click";
imageUpdatePanel.Triggers.Add(tr2);
AsyncPostBackTrigger tr3 = new AsyncPostBackTrigger();
tr3.ControlID = b3.ID;
//tr3.EventName = "Click";
imageUpdatePanel.Triggers.Add(tr3);
}
}
catch (Exception ex)
{
HandleException(ex);
}
}
}
void b1_Click(object sender, EventArgs e)
{
image1.Visible = true;
image2.Visible = false;
image3.Visible = false;
}
void b2_Click(object sender, EventArgs e)
{
image1.Visible = false;
image2.Visible = true;
image3.Visible = false;
}
void b3_Click(object sender, EventArgs e)
{
image1.Visible = false;
image2.Visible = false;
image3.Visible = true;
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
}
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
}
/// <summary>
/// Ensures that the CreateChildControls() is called before events.
/// Use CreateChildControls() to create your controls.
/// </summary>
/// <param name="e"></param>
protected override void OnLoad(EventArgs e)
{
if (!_error)
{
try
{
base.OnLoad(e);
this.EnsureChildControls();
// Your code here...
}
catch (Exception ex)
{
HandleException(ex);
}
}
}
/// <summary>
/// Clear all child controls and add an error message for display.
/// </summary>
/// <param name="ex"></param>
private void HandleException(Exception ex)
{
this._error = true;
this.Controls.Clear();
this.Controls.Add(new LiteralControl(ex.Message));
}
} }
Here's a related question though being asked in the context of SP 2010, it's still directly applicable given the solution.
We have a CQWP on our MOSS farm that does essentially the same thing: reads items from a list using jQuery and the SPServices plugin and animates slider changes. The most difficult part of the process is actually tweaking the look, if I remember correctly. Once you have the right pieces, putting it together is a snap.
I have dynamically generated a button an its event too.Now want to access a textbox (Generated Dynamically) into the onClick event of the Button.How can i do this?
You can declare it in class scope and use it in your button event handeler:
class MyClass
{
TextBox txtBox = null;
private void MyMethod()
{
var btn = new Button();
btn.Click += MyBtnEventHandler
...
txtBox = new TextBox();
}
protected void MyBtnEventHandler(object sender, .....)
{
if(txtBox != null) var data = txtBox.Text;
}
}
If you are adding dynamic textbox the page using Page.Controls.Add() or this.Controls.Add() then did you try using Page.FindControl(textBoxId) in button's onClick event? You have to set the ID of dynamic textbox while adding it during runtime.
I am trying to make a custom server control which inherits from DropDownList. I give the control an XML input containing some key/value pairs and my control shows them as a DropDownList.
I make the list items in the override Render method like this:
foreach (XElement child in root.Elements("Choice"))
{
string title = child.Element("Title").Value;
string score = child.Element("Score").Value;
item = new ListItem();
item.Text = title;
item.Value = score;
this.Items.Add(item);
}
The problem is that, when the user selects and item in the list, and the page posts back, the selected item is lost, and the list is re-initialized with the default data.
Does anyone have any idea how to keep the selected item, i.e. maintain the state?
Here is the complete source:
public class MultipleChoiceQuestionView2 : DropDownList
{
public MultipleChoiceQuestionView2() : base()
{
}
protected override void Render(HtmlTextWriter writer)
{
writer.RenderBeginTag(HtmlTextWriterTag.Table);
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
#region Parse Contets
if (!String.IsNullOrEmpty(this.Contents))
{
XElement root = XElement.Parse(this.Contents);
if (root.HasAttributes)
{
this.NoOfChoices = Int32.Parse(root.Attribute("ItemCount").Value);
}
this.Items.Clear();
this.Style.Add("width", "100px");
this.Style.Add("font-family", "Tahoma");
this.Items.Clear();
ListItem item = new ListItem();
item.Text = "";
item.Value = "0";
this.Items.Add(item);
foreach (XElement child in root.Elements("Choice"))
{
string title = child.Element("Title").Value;
string score = child.Element("Score").Value;
item = new ListItem();
item.Text = title;
item.Value = score;
this.Items.Add(item);
}
}
#endregion
base.Render(writer);
writer.RenderEndTag();
if (this.Required)
{
RequiredFieldValidator rfv = new RequiredFieldValidator();
rfv.ControlToValidate = this.ID;
rfv.InitialValue = "0";
rfv.Text = "*";
if (!String.IsNullOrEmpty(this.ValidationGroup))
{
rfv.ValidationGroup = this.ValidationGroup;
}
writer.RenderBeginTag(HtmlTextWriterTag.Td);
rfv.RenderControl(writer);
writer.RenderEndTag();
}
writer.RenderEndTag();
writer.RenderEndTag();
}
#region Properties
public string Contents
{
get
{
return ViewState["Contents"] == null ? "" : ViewState["Contents"].ToString();
}
set
{
ViewState["Contents"] = value;
}
}
private int mNoOfChoices;
public int NoOfChoices
{
get
{
return mNoOfChoices;
}
set
{
mNoOfChoices = value;
}
}
private string mValidationGroup;
public string ValidationGroup
{
get
{
return mValidationGroup;
}
set
{
mValidationGroup = value;
}
}
public string SelectedChoice
{
get
{
return "";
}
}
private bool mRequired = false;
public bool Required
{
get
{
return mRequired;
}
set
{
mRequired = value;
}
}
#endregion
}
Thanks in advance.
You've got two options: ViewState or ControlState.
The difference being ViewState can be overriden by setting EnableViewState="false" in the page directive, whilst ControlState cannot.
Essentially you need to hook into the state bag when you're getting/setting the values of the dropdown.
There's a decent example here where a custom control is derived from the Button class and maintains state between page requests - should fit your scenario nicely.
Hopefully that gets you started.