Can't change RootFolder of ASPxFileManager control using Callback method - devexpress

I'm using DevExpress 13.1 to develop my web application. My page has two controls: A Gridview which contains some item and a FileManager control (is children of a callbackpanel) which contain files information of item which is focused on that Gridview. I'm using Gridview's FocusRowChange client event to get data and send it back to server through an callback (of callback panel) to set new RootFolder value, but it not works. Tell me where's my wrong?
Thanks in advance.
My code:
ASPX file:
function myGridView_FocusRowChanged(s, e) {
var index = s.GetFocusedRowIndex();
var soCT = s.GetRowValues(index,"SoChungThu;SoHopDong",LoadFileList);
}
function LoadFileList(values) {
myCallbackPanel.PerformCallback("CHANGE_ROOT_FOLDER" + "," + values);
}
CS file:
protected void myCallbackPanel_Callback(object sender, DevExpress.Web.ASPxClasses.CallbackEventArgsBase e)
{
var vals = e.Parameter.Split(',');
if (vals[0].ToUpper() == "CHANGE_ROOT_FOLDER")
{
var path = vals[0] + "/" + vals[1];
myFileManager.Settings.RootFolder = path;
}
}
}

I found a solution.
Store folder path in Session, and assign it to RootFolder in Page_Load event.
Thank for reading.

Related

dynamically created controls within a usercontrol is not recognized

In the ascx.cs file I'm dynamically generating buttons. In .aspx file I add the control to the form. The control itself renders well, but when the buttons are clicked I get this error
An error has occurred because a control with id 'ctl03' could not be
located or a different control is assigned to the same ID after
postback.
DestopControl.ascx.cs
public partial class DesktopControl : PlaceHolder
{
public void Build()
{
for (int i = 0; i < 10; i++)
{
Button button = new Button()
{
Width = 50,
Height = 50,
ID = string.Format("button{0}", i),
Text = i.ToString()
};
button.Click+=new EventHandler(button_Click);
}
}
}
Default.aspx.cs
DesktopControl desktop = new DesktopControl();
desktop.Build();
MainContent.Controls.Add(desktop);
After reading the comments (little hard to read the code-part of the comments) it appears that yes, you are generating your controls inside an if(!isPostBack){}; well, looks like it's in the else part of that if statement.
You have to generate your controls every time the page posts back, as the page_load gets fired before your button click. So once the controls have been re-created the code will continue on to your button click handler, where the controls should be available to handle.
Essentially, take ReloadUI(Session["ui"]); OUT of the if(!isPostBack){}else{} statement. Put it after your if statement.
Like this:
if (!isPostBack){
// my first load code
}else{
// my postback code
}
// load all my dynamic controls here
ReloadUI(Session["ui"]);
Found a solution:
Every time there is a new UI I call this ClearScreen() which does the trick.
The error on 'ctl03' was a menu control which was generating it's own ID and somehow wasn't available on postback. I assigned an ID to it. But I guess all the issue went away with this ClearScreen() method.
private void ClearScreen()
{
try
{
List<Control> controls = new List<Control>();
foreach (Control control in MainContent.Controls)
{
controls.Add(control);
}
for (int i = 0; i < controls.Count; i++)
{
if (!(controls[i].GetType() == typeof(LiteralControl) || controls[i].GetType() == typeof(ScriptManager)))
{
MainContent.Controls.Remove(controls[i]);
}
}
}
catch (Exception ex)
{
}
}

Create a newEventHandler for a button. But Data fields are empty for some reason

I create a new event Handler to handle two different events. One is for saving a new document. The other is for saving an edit.
I added this in my Page_load:
if (Request.QueryString["ExhibitID"] != null)//new
{
if (!IsPostBack)
{
ddlCaseFiles.DataSourceID = "dsCaseFiles";
ddlCaseFiles.DataTextField = "Display";
ddlCaseFiles.DataValueField = "FileID";
rbByFileID.Checked = true;
rbMyFiles.Checked = false;
ddlCaseFiles.DataBind();
editExhibit(int.Parse(Request.QueryString["ExhibitID"]));//new
exhibitHeader.InnerText = "Edit Exhibit";
}
hidSavedExhibitID.Value = Request.QueryString["ExhibitID"];
saveExhibitBtn.Click += new EventHandler(this.btnUpdateExhibit_Click);
}
else
{
saveExhibitBtn.Click += new EventHandler(this.saveExhibitBtn_Click);
}
my save method for some reason keeps looping then crashing because the second time it goes through, there is no data since I reset it after the first save. I have no idea why it is running my save method twice.
this is my save method :
protected void saveExhibitBtn_Click(object sender, EventArgs e)
{
hidSavedExhibitID.Value = null;
int newExhibitID = saveExhibit();
int propertyID = autoCreateProperty(newExhibitID);
linkExhibitAndProperty(newExhibitID, propertyID);
SaveInfoIntoSessionVariables();
ClearFormFields();
}
the "saveExhibit()" method is where I actually access the DB and store everything. It works fine.
Because you re bind your datas in your Page_Load.
You must persist your datas with ViewState, EnableViewState="true"
You bind your datas just one time, in the ! IsPostBack. in order to not erase the selected values
If(! IsPostBack)
{
//Bind your datas with `DataBind()`
}

Get Selected Text asp.net custom server control

I need to get the latest text set in the custom control by javascript. When i tried to get the selected text from server control, it is always returning the default text & not the modified text. How to retain the latest value set by the javascript in servercontrol? Below is the complete code for your reference..
ServerControl1.cs
[assembly: WebResource("ServerControl1.Scripts.JScript1.js", "text/javascript")]
namespace ServerControl1
{
[DefaultProperty("Text")]
[ToolboxData("<{0}:ServerControl1 runat=server></{0}:ServerControl1>")]
public class ServerControl1 : WebControl
{
public List<string> ListItems
{
get
{
return ViewState["items"] as List<string>;
}
set
{
ViewState["items"] = value;
}
}
public string Text
{
get
{
return (FindControl("middleDiv").FindControl("anchorID") as HtmlAnchor).InnerText;
}
set
{
((FindControl("middleDiv").FindControl("anchorID") as HtmlAnchor)).InnerText = value;
}
}
protected override void CreateChildControls()
{
base.CreateChildControls();
HtmlGenericControl selectedTextContainer = new HtmlGenericControl("div");
selectedTextContainer.ClientIDMode = System.Web.UI.ClientIDMode.Static;
selectedTextContainer.ID = "middleDiv";
HtmlAnchor selectedTextAnchor = new HtmlAnchor();
selectedTextAnchor.ClientIDMode = System.Web.UI.ClientIDMode.Static;
selectedTextAnchor.ID = "anchorID";
selectedTextAnchor.HRef = "";
selectedTextContainer.Controls.Add(selectedTextAnchor);
HtmlGenericControl unList = new HtmlGenericControl("ul");
foreach (string item in ListItems)
{
HtmlGenericControl li = new HtmlGenericControl("li");
HtmlAnchor anchor = new HtmlAnchor();
anchor.HRef = "";
anchor.Attributes.Add("onclick", "updateData()");
anchor.InnerText = item;
li.Controls.Add(anchor);
unList.Controls.Add(li);
}
selectedTextContainer.Controls.Add(unList);
Controls.Add(selectedTextContainer);
ChildControlsCreated = true;
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
string resourceName = "ServerControl1.Scripts.JScript1.js";
ClientScriptManager cs = this.Page.ClientScript;
cs.RegisterClientScriptResource(typeof(ServerControl1), resourceName);
}
}
}
JScript1.js
function updateData() {
var evt = window.event || arguments.callee.caller.arguments[0];
var target = evt.target || evt.srcElement;
var anchor = document.getElementById("anchorID");
anchor.innerText = target.innerText;
return false;
}
TestPage Codebehind
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
List<string> items = GetDataSource();
ServerControl1.ListItems = items;
ServerControl1.Text = "Select ..";
}
}
protected void ClientButton_Click(object sender, EventArgs e)
{
string selectedText = ServerControl1.Text;
}
The server won't get your client changes unless you POST the changes to him. Your HtmlAnchors are being rendered in HTML as <a> controls, and these type of controls won't POST anything to the server.
You're going to need an <input> control to input the changes into the server (that's why they're called input controls after all). I suggest an <input type=hidden> to hold the value of the anchor.innerText and keeps its state.
Your Javascript function needs to be modified so it updates the anchor.innerText AND updates the hidden input value as well. This way when the page gets posted back to the server you can retrieve the updated and client-modified value from the hidden field.
First you need to define as private fields your selectedTextAnchor and the hiddenField you are going to insert. This is because you need to access them in your CreateChildControls method as well as in the getter and setter of yout Text property. Much in the way the partial designer classes define the controls you want to have available in code-behind.
ServerControl.cs
private HtmlAnchor selectedTextAnchor;
private HtmlInputHidden hiddenField;
In the CreateChildControls method you need to insert the hidden field.
You'll notice I removed the use of ClientIDMode.Static. Using that mode would make your client controls to have the same fixed IDs and Javascript might get confused when you have multiple copies of your ServerControl in a page, and thus losing the reusable purpose of a custom control.
Instead, you need to provide your Javascript function with the ClientID's of the controls it needs to modify. The key here is that you need to attach your controls to the Control's hierarchy BEFORE you try to get their ClientID's.
As soon as you do this.Controls.Add(dummyControl), you're making dummyControl to become a part of the Page and its dummyControl.ClientID will be suddenly changed to reflect the hierarchy of the page you're attaching it into.
I changed the order at which your controls are attached to the Control's collection so we can grab their ClientID's at the time we build the onclick attribute and pass the parameters so your Javascript function knows which anchor and hiddenField to affect.
ServerControl.cs
protected override void CreateChildControls()
{
base.CreateChildControls();
// Instantiate the hidden input field to include
hiddenField = new HtmlInputHidden();
hiddenField.ID = "ANCHORSTATE";
// Insert the hiddenfield into the Control's Collection hierarchy
// to ensure that hiddenField.ClientID contains all parent's NamingContainers
Controls.Add(hiddenField);
HtmlGenericControl selectedTextContainer = new HtmlGenericControl("div");
// REMOVED: selectedTextContainer.ClientIDMode = System.Web.UI.ClientIDMode.Static;
selectedTextContainer.ID = "middleDiv";
selectedTextAnchor = new HtmlAnchor();
// REMOVED: selectedTextAnchor.ClientIDMode = System.Web.UI.ClientIDMode.Static;
selectedTextAnchor.ID = "anchorID";
selectedTextAnchor.HRef = "";
selectedTextContainer.Controls.Add(selectedTextAnchor);
// Insert the selectedTextContainer (and its already attached selectedTextAnchor child)
// into the Control's Collection hierarchy
// to ensure that selectedTextAnchor.ClientID contains all parent's NamingContainers
Controls.Add(selectedTextContainer);
HtmlGenericControl unList = new HtmlGenericControl("ul");
foreach (string item in ListItems)
{
HtmlGenericControl li = new HtmlGenericControl("li");
HtmlAnchor anchor = new HtmlAnchor();
anchor.HRef = "";
// The updateData function is provided with parameters that will help
// to know who's triggering and to find the anchor and the hidden field.
// ClientID's are now all set and resolved at this point.
anchor.Attributes.Add("onclick", "updateData(this, '" + selectedTextAnchor.ClientID + "', '" + hiddenField.ClientID + "')");
anchor.InnerText = item;
li.Controls.Add(anchor);
unList.Controls.Add(li);
}
selectedTextContainer.Controls.Add(unList);
}
Note the use of the keyword this in the updateData function, it'll help us to grab the object that is triggering the action. Also note that both Id's are passed as strings (with single quotes)
The Javascript function would need to be modified so it updates the anchor and the hidden input field.
JScript1.js
function updateData(sender, anchorId, hidFieldId) {
// Update the anchor
var anchor = document.getElementById(anchorId);
anchor.innerText = sender.innerText;
// Update the hidden Input Field
var hidField = document.getElementById(hidFieldId);
hidField.value = sender.innerText;
return false;
}
The last thing to do is change the way you are setting and getting your Text property.
When you GET the property you need to check if it's a Postback, and if it is, then you want to check if among all the info that comes from the browser there is your HiddenInputField. You can grab all the info coming from the client right at the Request object, more specifically, in the Request.Form.
All enabled input controls on your page will be part of the Request.Form collection, and you can get their values by using Request.Form[anyInputControl.UniqueID]. Note that the key used for this object is the UniqueID, NOT ClientID.
Once you get your client-modified value from the hidden input, you assign its value to the selectedTextAnchor, otherwise it'll go back to the original "Select..." text.
When you SET the property, you just need to assign it to the selectedTextAnchor.
In both GET and SET you need to call EnsureChildControls(), which will actually call your CreateChildControls() to make sure that your selectedTextAnchor and hiddenField controls are instantiated before you try to get some of their properties. Pretty much the same way that it's done in Composite Controls.
ServerControl.cs
public string Text
{
get
{
EnsureChildControls();
if (this.Page.IsPostBack)
{
string HiddenFieldPostedValue = Context.Request.Form[hiddenField.UniqueID];
// Assign the value recovered from hidden field to the Anchor
selectedTextAnchor.InnerText = HiddenFieldPostedValue;
return HiddenFieldPostedValue;
}
else
{
return selectedTextAnchor.InnerText;
}
}
set
{
EnsureChildControls();
selectedTextAnchor.InnerText = value;
}
}
This way you can have a control that recognizes the changes made in client. Remember that server won't know any change in client unless you notice him.
Another approach would be to notice the server everytime you click a link through an ajax request, but this would require a whole new different code.
Good luck!

Selected value in asp.net dropdown in a repeater not returned

I've currently go a very strange problem. I'm using an asp.net wizard to upload some files. The files are uploaded using plupload. After the files have uploaded I have a list of the upload files stored in a session variable. I use the session variable to create a table showing the upload files. The user now has option to set a file category using a dropdown in the table. When the user clicks 'finish' button the code reads the list of files and the category from the table. The odd thing is this code works fine on my development machine and on several servers but on a particular clients server the drop down value always returns as null. Here is the relevent code:
protected void Page_Init(object sender, EventArgs e)
{
bindRepeater();
}
private void bindRepeater()
{
ArrayList sessionFiles = (ArrayList)Session["PLUploadFiles"];
IList<document> files = new List<document>();
foreach (string fileName in sessionFiles)
{
document doc = new document();
doc.FileName = fileName;
doc.Description = fileName.Split('.').First();
files.Add(doc);
}
TableRepeater.DataSource = files;
TableRepeater.DataBind();
}
protected void SaveButton_Click(object sender, EventArgs e)
{
foreach (RepeaterItem item in TableRepeater.Items)
{
Label descriptionLabel = (Label) item.FindControl("DescriptionLabel");
String description = descriptionLabel.Text;
Label fileNameLabel = (Label)item.FindControl("FileNameLabel");
String fileName = fileNameLabel.Text;
DropDownList categoryDropDown = (DropDownList) item.FindControl("CategoryDropDownList");
string category = categoryDropDown.SelectedValue;
if(SaveClicked != null)
{
SaveEventArgs s = new SaveEventArgs();
s.FileName = fileName;
s.Category = category;
s.Description = description;
SaveClicked(this, s);
}
}
Response.Redirect(RedirectURL);
}
Note that the entire wizard lives on a usercontrol. Has anybody got any idea why this code works fine on most machines but fails on one particular server?
Looks like I've fixed it. For some reason I was seeing a double postback. This was calling my code to reset the session variables in Page_Load at the wrong time. The work around is to reset the session variables in the page that links to the upload page so they are reset before the page is loaded. I've no idea why I'm seeing the double postback.

ASP.NET Dynamic User Control with JQuery

Alright...this is a bit of a complex problem so hopefully I can explain it properly.
I have a user control which I am dynamically loading in my page_load event via a method (see below). The user control contains a gridview and a label. A key piece of information has to do with how to get around the convenient feature of gridviews not rendering when their datasource is empty. In my user control I add some hidden rows so that the grids will render and the user can see just the headers (if the situation calls for it).
The nomControl is an asp:Panel on the parent page which will hold the user controls. The dsRefinedProductsNomInfo is a strongly typed dataset.
private void LoadCycleControls()
{
var dsRefinedProductsNomInfo = Session[REFINED_PRODUCT_NOMINATION_INFO] as RefinedProductsNomInfo;
if (dsRefinedProductsNomInfo == null)
{
return;
}
int permittedCycles = dsRefinedProductsNomInfo.NOS_MONTH.Count == 0 ? 0: dsRefinedProductsNomInfo.NOS_MONTH[0].PERMITTED_CYCLES;
for (int cycle = 1; cycle <= permittedCycles; cycle++ )
{
var control = LoadControl("~/CustomControl/RefinedProductNominationCycleControl.ascx");
nomContent.Controls.Add(control);
var nomControl = control as RefinedProductNominationCycleControl;
if (nomControl == null)
{
return;
}
nomControl.CycleNumber = cycle;
nomControl.ID = "control_" + cycle;
nomControl.CycleTitle = "Cycle " + cycle;
nomControl.GridDataSource = dsRefinedProductsNomInfo.REFINED_PRODUCT_NOS_CYCLE_INFO;
}
}
Now when a user adds a row to the grid they click a plus button. In the button javascript click event I make an ajax call to a page method.
var options = {
type: "POST",
url: "RefinedProductNomination.aspx/AddNomCycleLineItem",
data: "{'id':'" + tableRow.attr("id") + "',\
'isPlug':'" + isPlug + "',\
'sequenceNbr':'" + sequenceNbr + "',\
'receiptLocationId':'" + receiptLocationId + "',\
'materialTypeId':'" + materialId + "',\
'shipperId':'" + shipperId + "',\
'tankId':'" + tankId + "',\
'deliveryLocationId':'" + deliveryLocationId + "',\
'volume':'" + volume + "',\
'cycle':'" + cycle + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(response) {
if (response.d != "") {
if (response.d == "-1000") {
var messageContainer = tableRow.parents("div").siblings("div #messageSummary");
messageContainer.empty()
var message = $("<span></span>").append("There has been an issue accepting the row please try again.");
messageContainer.append(message);
message.fadeOut(10000, "linear");
}
else {
ConvertToReadOnlyRow(tableRow, response.d);
}
}
}
};
//Call the PageMethods
$.ajax(options);
The page method then retrieves the dataset from the cache and adds the new row the user created. This all works fine and I can save to the database via an asp:button and handling it's click event.
My issue is after the the user clicks the save button and everything is rendered my grid shows the rows I added to make sure just the headers show up. In my save button click event I am removing these added rows so they don't get persisted and then saving and then added again once we load the user control. Initially this seems like the right place to handle this but after figuring out the order of events it would appear I was wrong.
So my question. Can anyone suggest how I should be handling my events so that my rendered grid is up to date and not showing these hidden rows. I have a feeling I am just doing things in the wrong place/order but this is my first real swim in the deep end of the asp.net pool. If any more information would be helpful let me know.
Thank you in advance for any help.
Well I think I have solved my own problem. Essentially what I have done is this:
1. On parent page_load I reload controls so that they show up on the screen.
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
LoadCycleControls();
return;
}
RetrieveParameters();
LoadRefinedNominationInfo();
LoadLookupLists();
LoadCycleControls();
}
2. On control page_load I check IsPostBack. If it's true I just return.
protected void Page_Load(object sender, EventArgs e)
{
if(IsPostBack)
{
return;
}
BindData();
cycleNumber.Value = _cycleNumber.ToString();
}
3. On parent save button click, which caused the post back, I do my normal save logic. After that is complete I iterate over all the controls I created set their data source to the updated dataset. In my control I exposed a method called BindData() which I then call.
protected void BtnSaveClick(object sender, EventArgs e)
{
SaveRefinedProductNosInfo();
var dataSet = RefinedProductsNomInfoCache;
if (dataSet == null)
{
return;
}
foreach (var nomControl in nomContent.Controls.OfType<RefinedProductNominationCycleControl>())
{
nomControl.GridDataSource = dataSet.REFINED_PRODUCT_NOS_CYCLE_INFO;
nomControl.BindData();
}
}
Now even though I am slightly new at this, it feels a little dirty which probably means I am not doing things quite right still so if someone actually knows whether I am doing this right or not cares to comment that would be great :)

Resources