Sharepoint web parts Rendering html and controls - sharepoint

I have a webpart that displays HTML output within the RenderWebPart method and also creates controls within the CreateChildControls both methods are declared as overridden in the webpart.
My question is how to I control the order of the display of the controls and html output?
At the moment I call EnsureChildControls() within the RenderWebPart mthod to ensure all controls within the CreateChildControls are created and then the html out is rendered.
What if I wanted to display a control on the page then html output and then another control below in that order?

I would recommend moving all of your static HTML out of the Render function and into the CreateChildControls function. If you need to, you can add regular old HTML using Labels, WebControls, or even better... LiteralControls. Then you can just add them to your Controls collection.
Example:
WebControl container = new WebControl(System.Web.UI.HtmlTextWriterTag.Div);
StringBuilder sb = new StringBuilder();
sb.Append("<ul>");
foreach (Node child in this.Children)
{
sb.AppendFormat("<li>{1}</li>", url, name);
}
sb.Append("</ul>");
LiteralControl l = new LiteralControl();
l.Text = sb.ToString();
container.Controls.Add(l);

I'm actually relatively new to SharePoint and I was very astounded initially that one had to create individual controls manually, without a GUI interface like any normal ASP.NET web development involves. However, I had a very very good tip that allowed me to still use a GUI interface, and use it to create webparts for Sharepoint. It involves wrapping WebUserControls in webparts.
The link I used is here: http://www.a2zdotnet.com/View.aspx?id=95
You basically create WebUserControls (.ascx file) in a website, and so you can just add your controls like any normal .aspx page. You can also have a normal code-behind file (.ascx.cs). You then drag the .ascx file onto an .aspx file, so that it will then use your WebUserControl. When your .ascx files are ready and built, you copy them to the Layouts directory in the 12-Hive of your SharePoint Server. Best to create a sub-directory in there, to avoid clashing with other files in there already.
You then need to create a separate class Library project, that will have your WebPart code on. You then tell your WebPart to use your .ascx files in the layouts directory. Something like this:
protected override void CreateChildControls()
{
base.CreateChildControls();
try
{
this.Controls.Clear();
_myControl = this.Page.LoadControl("\\_layouts\\MyFolder\\WebUserControl.ascx");
this.Controls.Add(_myControl);
}
catch (Exception e)
{
err = e.Message;
}
The link I provided above provides more information, but basically you compile the webpart project and then add the DLL to the BIN directory of your sharepoint server (c:\inetpub\wwwroot\wss\ etc). You don't have to compile it to the GAC, by the way.
Then you add a entry to the web.config of your sharepoint server:
<SafeControl Assembly="MyWebUserControl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9f4da00116c38ec5" Namespace="MyWebUserControl" TypeName="*" Safe="True" />
If you didn't compile the DLL to the GAC, but the BIN instead, you just need:
<SafeControl Assembly="UserControl" Namespace="UserControl" TypeName="*" Safe="True" />
Again, the link I posted above has it written in the code, a reference to the GUID, which is only needed if you placed the DLL in the GAC. You don't need the GUID part of the code if you only placed in the BIN directory.
Hope that helps.
Ash

Related

Cannot use attribute forms in page template?

I am using JDeveloper 11.1.2.3.0
I have to show a popup by clicking a link that is located in the page template. For this I created a popup within the pageTemplate then inserted a dialogBox and within the dialog box I dragged and dropped my VO from the DataControl panel and inserted it as an ADF form. The problem is that when I run and click the link (that contains the "ShowPopupBehavior") I am getting this error:
//C:/Oracle/Middleware/jdeveloper/jdev/system11.1.2.3.39.62.76.1/MyNew/ViewControllerWebApp.war/WEB-INF/templates/myTemplates.jsf #58,118 value="#{bindings.TypeName.inputValue}": Target Unreachable, 'TypeName' returned null
ADF_FACES-60097:For more information, please see the server's error log for an entry beginning with: ADF_FACES-60096:Server Exception during PPR, #2
This happens for every View that I can insert here. Is this comming because I am not allowed to insert ADF forms within the page template?
If so please give me a hint to achieve what I explained in the first sentence.
I just figured out the solution to this problem. Each page has its own bindings, so a page that uses the templates (or if want to use bindings from other pages) has to declare that page in the Executables section of the page Bindings. The new executable should have the ID of the page (of the template in this case) and the path of the page. Then the bindings of the template can be accessed as explained here:
public String cb1_action() {
BindingContext bctx = BindingContext.getCurrent();
DCBindingContainer bindings =
(DCBindingContainer)bctx.getCurrentBindingsEntry();
//access the page template Pagedef file reference in the
//Executable section of the consumer page's Pagedef file
DCBindingContainer templateBinding =
(DCBindingContainer)bindings.get("ptb1");
//get the MethodBinding
OperationBinding printMethod =
(OperationBinding)templateBinding .get("printThis");
//invoke the print method exposed on the template's PageDef file
printMethod.getParamsMap().put("message","Hello World");
printMethod.execute();
return null;
}
https://blogs.oracle.com/jdevotnharvest/entry/how_to_invoke_adf_bindings
ps: Pay attention not to bind the value of the template in your page ex: value="#{bindings.ptb1}" - it is a bit strange but in this case you will not get the page bindings and will get only the template ones.
The value property containing #{bindings.ptb1} should be removed from the pageTemplate tag but the ptb1 reference has to be in the pages PageDef file.

SharePoint - Custom document library with folder structure

I have a custom document library template with content types. This works fine but the only thing that I would like to add is that when a user instantiates a new document library based on that template, that is has a predefined folder structure already in place.
I have tried adding Module tags in my schema.xml but this doesn't seem to work.
I know that it is possible to provision a document library with files and folders with a ListInstance feature but this is not possible in this case. I would like that the predefined folder structure is part of the document library template.
Is this possible?
Thanks
Maarten
If You want to achieve this using Document Library Definition. I don't think that would be achievable. What you can do is take help of list /document library templates.
1 Create a custom Doclibary the way you want.
2. create the desired folder structure. without uploading any documents.
3, Save the doc library as template by going to Doclibray settings ( make sure you store the template along with content stored into it)
Another method (which I must blog on soon) is to fake a list creation event. I add an empty view definition with a custom aspx page to the list template. The custom page simply executes some custom functionality on the list, deletes the initialisation view, then redirects to the normal view. It's a little messy, and it will only work if the list is created through the UI, but it works.
Here is a very quick example. You already have your list template. In the schema.xml file, add a new View to the Views element like so:
<Views>
<!-- Below is a blank view used to kick of initialisation after list creation. -->
<View DisplayName="Initialise" Type="HTML" DefaultView="TRUE" WebPartZoneID="Main" SetupPath="pages\Scratch\init.aspx" Hidden="TRUE" Url="_init.aspx">
<Toolbar Type="Standard" />
<ViewHeader />
<ViewBody />
<ViewFooter />
<ViewEmpty />
<ViewFields />
<ViewData />
<Query />
</View>
<!-- standard views would be here -->
</Views>
You may be able to go without the empty elements in there. That was something I was going to test further before blogging on it. But this will get the job done. The important things are:
This view is the first view and DefaultView is set to TRUE.
The SetupPath is set to a custom page that you will provision with your solution.
For the custom page (init.aspx in my example), I just made a copy of ...\12\TEMPLATE\Pages\viewpage.aspx and changed what the page inherits from. You could do this with inline code, but I used a codebehind assembly. So first line of that file becomes:
<%# Page language="C#" MasterPageFile="~masterurl/default.master" Inherits="SharePointScratch.InitPage,SharePointScratch,Version=1.0.0.0,Culture=neutral,PublicKeyToken=xxxxxxxxxxxxxxxx" %>
And then the codebehind:
using System;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
namespace SharePointScratch
{
public class InitPage : System.Web.UI.Page
{
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
SPList list = SPContext.Current.List;
list.ParentWeb.AllowUnsafeUpdates = true;
// Create you folder structure here...
// Fix the views by deleting the initialisation view.
SPView view = SPContext.Current.ViewContext.View;
list.Views.Delete(view.ID);
list.Update();
list.ParentWeb.AllowUnsafeUpdates = false;
// Redirect to the new default view.
SPUtility.Redirect(list.DefaultViewUrl, SPRedirectFlags.Default, this.Context);
}
}
}
Basically, we are relying on the SharePoint default behavior to display the default view of a list after creation. A custom view is inserted in the schema with the sole intention of firing off some custom code. The custom code does, well, whatever you want. After this, you clean up by deleting the special view from the template and redirecting back to the view.

Feature element repeatedly added with every feature activation/deactivation

This is a very minor behavior when compared with the entire scope, but it is one that I'd like to put a stop to.
I have created a very, very simple SharePoint Feature. It has two elements in its manifest: an aspx webpart page, and an elements xml. I'll paraphrase my elements xml, which just adds a module, below.
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Module Name="Pass" Url="" Path="">
<File Url="pasq.aspx" NavBarHome="True" Type="Ghostable">
<AllUsersWebPart WebPartZoneID="Left" WebPartOrder="0">
<![CDATA[
WARGH THIS PART DOESN'T MATTER FOR THIS QUESTION!
]]>
</AllUsersWebPart>
</File>
</Module>
</Elements>
Now, on the first time I deploy and activate this feature, it works properly. But if I have to deactivate and then reactivate the feature in order to fix some properties in the webpart, then I find myself with a second webpart on the page. Naturally, each similar cycle will just add more and more. I understand that a new webpart must be created in order to employ the changes I just made, but why is the old webpart still on the page? Can I make this older webpart go away automatically as part of the feature activation/deactivation process without needing to employ a Receiver class?
EDIT
Based on the fact that I've already employed a Receiver to solve this issue, I ended up just adding the webpart removal as part of feature deactivation. But I was still hoping that maybe there's something I'm missing.
Unfortunately the content will be repeated unless you do one of the following :
Solution 1 : you can add a similar code to the activate feature to add webparts in the pages as follows:
SPFile file = page.File;
using (SPLimitedWebPartManager WebPartManager =
file.GetLimitedWebPartManager(PersonalizationScope.Shared))
{
try
{
SPLimitedWebPartCollection webparts = WebPartManager .WebParts;
if (webparts.Count == 0)
{
//set your web part
WebPartManager.AddWebPart(webpart, "MomoZone", 1);
}
}
catch(Exception ex)
{
throw;
}
finally
{
WebPartManager.Web.Dispose();
}
}
Solution 2 : you can use site definition with and Onet file that runs only once the site is created so you would have no more of this problem while setting your efatures to hidden
Cheers
SharePoint doesn't offer a declarative way (xml) to remove feature elements automagically. You'll have to add some code in a FeatureDeactiving method on the feature receiver to remove it programatically, sorry.

Sharepoint-customizing usercontrol property in smartpart

If anyone is having idea how to customize properties in a smartpart. I have created usercontrol and i m wrappin it in a smartpart.I want to upload my xml from Document library.
private string feedXML;
[Browsable(true),
Personalizable(true) ]
public string FeedXML
{
get
{ return feedXML; }
set
{ feedXML = value; }
}
and I am using this like
//
feedXML="\customxml.xml";
XPathDocument doc = new XPathDocument(Server.MapPath(feedXML));
but this thing is not working . When I am clicking on modify shared webpart of sharepoint page is not rendering. Any clue where I m getting wrong.
You might want to verify the result of your server.mappath statement. It will be something like C:\Inetpub...
So your code is trying to retrieve a file from the filesystem that really lives in SharePoint because you have uploaded it to a Document Library.
If you want that file you'll have to retrieve it using the SharePoint object model, have a look at the GetFileAsString method.
I agree with Denni..
Seems like Smartpart is only making it more difficult? What advantages does it have?
I make my own webpart containers for ascx controls.. very little work and all the control you need. No problems with trust settings either.
Are you sure this is correct?
feedXML="\customxml.xml";
Perhaps, what you want is:
feedXML="\\customxml.xml"; //escape the back-slash.
or
feedXML="/customxml.xml"; // use the forward-slash.
Anyway, if you just want to wrap your user control inside a Web part, you don't need the SmartPart. You can write your custom Web part yourself quite easily.

How to use the SharePoint MultipleLookupField control?

I want to use the MultipleLookupField control in a web page that will run in the context of SharePoint. I was wondering if anyone would help me with an example, which shows step by step how to use the control two display two SPField Collections.
I'm not entirely sure I understand your question, especially the bit about displaying two SPField collections. Sorry if this turns out to be the answer to a completely different question!
Anyway here's a quick demo walkthrough of using the MultipleLookupField in a web part.
Create a team site. Add a few tasks to the task list. Also put a document in the Shared Documents library. Create a new column in the Shared Documents library; call it "Related", have it be a Lookup into the Title field of the Tasks list, and allow multiple values.
Now create a web part, do all the usual boilerplate and then add this:
Label l;
MultipleLookupField mlf;
protected override void CreateChildControls()
{
base.CreateChildControls();
SPList list = SPContext.Current.Web.Lists["Shared Documents"];
if (list != null && list.Items.Count > 0)
{
LiteralControl lit = new LiteralControl("Associate tasks to " +
list.Items[0].Name);
this.Controls.Add(lit);
mlf = new MultipleLookupField();
mlf.ControlMode = SPControlMode.Edit;
mlf.FieldName = "Related";
mlf.ItemId = list.Items[0].ID;
mlf.ListId = list.ID;
mlf.ID = "Related";
this.Controls.Add(mlf);
Button b = new Button();
b.Text = "Change";
b.Click += new EventHandler(bClick);
this.Controls.Add(b);
l = new Label();
this.Controls.Add(l);
}
}
void bClick(object sender, EventArgs e)
{
l.Text = "";
foreach (SPFieldLookupValue val in (SPFieldLookupValueCollection)mlf.Value)
{
l.Text += val.LookupValue.ToString() + " ";
}
SPListItem listitem = mlf.List.Items[0];
listitem["Related"] = mlf.Value;
listitem.Update();
mlf.Value = listitem["Related"];
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
EnsureChildControls();
}
Granted, this is borderline ridiculous -- everything is hard-coded, there is no error-handling at all, and it serves no useful purpose -- but it's only meant as a quick demo. Now build and deploy this web part and add an instance of it to your team site's homepage; it should allow you to get and set the tasks which are associated with the first document in the library.
The strange bit towards the end of the button Click handler, where we read a value from mlf.Value and then write it back again, appears to be required if you want the UI to stay in sync with the actual list values. Try omitting the last line of bClick to see what I mean. This has been driving me nuts for the last hour or so, and I'm hoping another commenter can come up with a better approach...
Hm. Works fine on mine, so let's see if we can work out how your setup is different...
It looks as though it's having trouble populating the control; my first guess would be that this is because the code makes so many assumptions about the lists it's talking to. Can you check that you've got a plain vanilla Team site, with (assume these names are case-sensitive):
A list called Tasks, with several items in it
A library called Shared Documents with at least one document
A column called Related in the Shared Documents library
The Related column is a Lookup field into the Title column of Tasks, and allows multiple values.
The first document in Shared Documents has a value for Related
Then add the webpart. Fingers crossed...
Hm. OK, I'm still trying to break mine... so I went to the layouts directory and created a file foo.aspx. Here it is:
<%# Page Language="C#" Inherits="System.Web.UI.Page" MasterPageFile="~/_layouts/simple.master" %>
<%# Register Tagprefix="foo" Namespace="Foople" Assembly="Foople, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9f4da00116c38ec5"%>
<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">
<foo:WebPart1 id="fred" runat="server" />
<foo:WebPart1a id="barney" runat="server" />
</asp:Content>
WebPart1 is the webpart from before. WebPart1a is the exact same code, but in a class that inherits directly from WebControl rather than from WebPart.
It works fine, apart from a security validation problem on the postback that I can't be bothered to debug.
Changing the masterpage to ~masterurl/default.master, I uploaded foo.aspx to the Shared Documents library, and it works fine from there too -- both the WebControl and the WebPart behave properly, and the security problem is gone too.
So I'm at a loss. Although I did notice this page with an obscure might-be-bug which is also in SPFolder.get_ContentTypeOrder(): http://forums.msdn.microsoft.com/en-US/sharepointdevelopment/thread/63baf273-7f36-453e-8293-26417759e2e1/
Any chance you could post your code?

Resources