2

I am using sp 2013. I have created a farm visual webpart. I created some webpart properties. But I would like to create some webpart property like a publish image. With this webpart property it would be possible to select an image from a library. In my codebehind I would like to do some logic with this image. Someone know how to?

1
  • Are you talking about file control in webpart properties to select images from either library or file server?
    – ateet
    Sep 24, 2014 at 8:09

3 Answers 3

4
+25

What you're asking is a bit complex to implement, but it's possible. You need to use AssetPickerDialog to get the same behavior as what you've mentioned, to pick up the image from library.

I've implemented AssetPicker once, but that's for a different implementation, kind of searching entity from custom database. And that AssetPicker was triggered from a custom button.

For your case, what you need to do is:

Custom ToolPart: ToolPart class to implement AssetPickerDialog

The idea is to create 3 controls: TextBox, Button, and LiteralControl. A good article can be found in this link. The first key part is in the code below:

    protected override void CreateChildControls()
    {
        base.CreateChildControls();

        Controls.Add(sl);
        Controls.Add(txt);
        Controls.Add(btn);

        string strRelativeWebURL = SPEncode.HtmlEncode(SPControl.GetContextWeb(Context).ServerRelativeUrl);
        if (strRelativeWebURL.Trim() == "/")
        {
            strRelativeWebURL = ""; //blank browses the root spweb
        }
        string strAssetPickerConfig = string.Format("<script type='text/javascript'>with(new AssetPickerConfig('testAssetPickerObj')){{DefaultAssetImageLocation='';CurrentWebBaseUrl='{0}';OverrideDialogFeatures='';OverrideDialogTitle='';OverrideDialogDesc='';OverrideDialogImageUrl='';AssetUrlClientID='{1}';AssetTextClientID='';UseImageAssetPicker=true;/* make this false to show Documents instead*/ DefaultToLastUsedLocation=true;DisplayLookInSection=true;ReturnCallback = null;}}</script>", strRelativeWebURL, txt.ClientID);
        lit.Text = strAssetPickerConfig;
        Controls.Add(lit);

        btn.OnClientClick = "APD_LaunchAssetPickerUseConfigCurrentUrl('testAssetPickerObj'); return false;";
    }

Basically it will just adds those 3 controls, and assign the button with AssetPickerDialog. OnClientClick will assign the AssetPicker, and return value (typically the URL of the image) will be set to the textbox (in this case, control name is "txt").

The second key part is in the code below:

    public override void ApplyChanges()
    {
        WebPart1 parentWP = (ImagePickerWebPart)this.ParentToolPane.SelectedWebPart;
        parentWP.SelectedImageURL = txt.Text;
    }
    public override void SyncChanges()
    {
        EnsureChildControls();

        WebPart1 parentWP = (ImagePickerWebPart)this.ParentToolPane.SelectedWebPart;
        txt.Text = parentWP.SelectedImageURL;
    }

In this section above, you need to assign Parent's webpart property (in this case is SelectedImageURL) once "Apply" button in the webpart's toolpart area is clicked. You may notice that ParentToolPane.SelectedWebPart is the webpart Type which you want to add the ToolPart (see the custom webpart section below).

For reference, below is the full code:

public class ImagePickerToolPart : ToolPart
{
    TextBox txt;
    Button btn;
    ScriptLink sl;
    Literal lit;
    public ImagePickerToolPart()
    {
        this.Init += new EventHandler(ImagePickerToolPart_Init);
    }
    private void ImagePickerToolPart_Init(object sender, EventArgs e)
    {
        txt = new TextBox();
        btn = new Button();
        sl = new ScriptLink();
        lit = new Literal();

        sl.Name = "AssetPickers.js";
        sl.Localizable = true;
        sl.Language = "javascript";

        btn.Text = "...";

        SyncChanges();
    }
    public override void ApplyChanges()
    {
        WebPart1 parentWP = (ImagePickerWebPart)this.ParentToolPane.SelectedWebPart;
        parentWP.SelectedImageURL = txt.Text;
    }
    public override void SyncChanges()
    {
        EnsureChildControls();

        WebPart1 parentWP = (ImagePickerWebPart)this.ParentToolPane.SelectedWebPart;
        txt.Text = parentWP.SelectedImageURL;
    }

    protected override void CreateChildControls()
    {
        base.CreateChildControls();

        Controls.Add(sl);
        Controls.Add(txt);
        Controls.Add(btn);

        string strRelativeWebURL = SPEncode.HtmlEncode(SPControl.GetContextWeb(Context).ServerRelativeUrl);
        if (strRelativeWebURL.Trim() == "/")
        {
            strRelativeWebURL = ""; //blank browses the root spweb
        }
        string strAssetPickerConfig = string.Format("<script type='text/javascript'>with(new AssetPickerConfig('testAssetPickerObj')){{DefaultAssetImageLocation='';CurrentWebBaseUrl='{0}';OverrideDialogFeatures='';OverrideDialogTitle='';OverrideDialogDesc='';OverrideDialogImageUrl='';AssetUrlClientID='{1}';AssetTextClientID='';UseImageAssetPicker=true;/* make this false to show Documents instead*/ DefaultToLastUsedLocation=true;DisplayLookInSection=true;ReturnCallback = null;}}</script>", strRelativeWebURL, txt.ClientID);
        lit.Text = strAssetPickerConfig;
        Controls.Add(lit);

        btn.OnClientClick = "APD_LaunchAssetPickerUseConfigCurrentUrl('testAssetPickerObj'); return false;";
    }
}

Custom WebPart: Adding the Custom ToolPart to your Webpart

We need to add the custom ToolPart class to your webpart. Typically by doing override to GetToolParts() method will do. Below is the code:

    public override ToolPart[] GetToolParts()
    {
        ToolPart[] toolparts = new ToolPart[3]; //this section, need to extend a bit more
        WebPartToolPart wptp = new WebPartToolPart(); //this section is pre-defined
        CustomPropertyToolPart custom = new CustomPropertyToolPart(); //this section is predefined
        toolparts[0] = custom;
        toolparts[1] = wptp;

        // This is the custom ToolPart you've just created above
        toolparts[2] = new ImagePickerToolPart(); //this is your custom class to be added

        return toolparts;
    }

Your custom toolpart must be added to the ToolParts collection. In the example, added it as the last.

        toolparts[2] = new ImagePickerToolPart();

aaaand below is the full code of the webpart:

public class ImagePickerWebPart : Microsoft.SharePoint.WebPartPages.WebPart
{
    private const string defaultText = "/";
    private string text = defaultText;

    [Browsable(false), Category("Image"),
    DefaultValue(defaultText),
    WebPartStorage(Storage.Personal),
    FriendlyName("Image to the library"), Description("Text Property")]
    public string SelectedImageURL
    {
        get
        {
            return text;
        }

        set
        {
            text = value;
        }
    }

    /// <summary>
    /// Gets the custom tool parts for this Web Part by
    /// overriding the GetToolParts method of the WebPart
    /// base class. You must implement custom tool parts in
    /// a separate class that derives from
    /// Microsoft.SharePoint.WebPartPages.ToolPart.
    /// </summary>
    ///<returns>
    /// An array of references to ToolPart objects.
    ///</returns>
    public override ToolPart[] GetToolParts()
    {
        ToolPart[] toolparts = new ToolPart[3]; //this section, need to extend a bit more
        WebPartToolPart wptp = new WebPartToolPart(); //this section is pre-defined
        CustomPropertyToolPart custom = new CustomPropertyToolPart(); //this section is predefined
        toolparts[0] = custom;
        toolparts[1] = wptp;

        // This is the custom ToolPart you've just created above
        toolparts[2] = new ImagePickerToolPart(); //this is your custom class to be added

        return toolparts;
    }

    /// <summary>
    /// Render this Web Part to the output parameter specified.
    /// </summary>
    /// <param name="output">
    /// The HTML writer to write out to
    /// </param>
    protected override void RenderWebPart(HtmlTextWriter output)
    {
        output.Write(SPEncode.HtmlEncode("Your custom text is: <b>" + this.Text + "</b><hr>"));

    }
}

You will notice that I have a webpart property called SelectedImageURL, this will have your image URL once it is saved. Hope it helps! ;)

Reference:

MSDN: Create a Web Part with custom Tool Part

Blog: Using SharePoint Image Picker

3

This can be definitely possible while using asset dialog provided OOTB in SharePoint. This dialog uses AssetPickers.js file present in _layouts/15 directory of SharePoint server.

I found one blog and try it on my side by creating visual webpart and make the file selector as one of its properties.

Link of Blog:-http://fahadzia.com/blog/2009/11/using-sharepoint-image-picker-to-select-images/

While creating solution I have added dropdown as a custom property in webpart for my own poc. So you can neglect that part. And try to follow step as I am mentioning below exactly. Because this project is perfectly working with no errors. Below webpart functionality is selecting a list from dropdown will show first 5 item from list in visual webpart. I know that's not your requirement.

So I integrated your required functionality in my solution which serve the purpose of selecting asset from SharePoint and populating its url in textbox. I haven't read this url property in Synch or Apply overridden function as that don't required for me. But you can do the same as I do for dropdown.

So at the end it look like below screen shot Webpart Properties editor Appear when you click on browse button After selecting file, its url will be populated in textbox

Please see below code, it is working perfectly. It involve a series of steps which are:-

  1. Create a Solution in visual studio with structure like this: Solution Structure

  2. Note I have added AssetPickers.js as an existing item from _layouts/15 directory and you have to do the same. And add HTMLEditor.cs file as a class file which server the purpose od editorpart for visual webpart.

  3. Add Code to you HTMLEditor.cs file given below: Starting part of code

    public HtmlEditor() { this.ID = "HtmlEditor"; }

    private void populateListDdl()
    {
        ddlList.Items.Clear();
        ddlList.Items.Add(new ListItem("-Select List-",string.Empty));
        SPSecurity.RunWithElevatedPrivileges(delegate()
        {
            try
            {
                using (SPSite site = new SPSite("http://win-8c97ll22qqc:100/sites/dev"))
                {
                    using (SPWeb web = site.OpenWeb())
                    {
                        SPListCollection listColl = web.Lists;
                        foreach (SPList list in listColl)
                        {
                            if (list.BaseTemplate == SPListTemplateType.GenericList)
                            {
                                ddlList.Items.Add(new ListItem(list.Title, list.Title));
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Custom Properties VWP", TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, ex.Message, ex.StackTrace);
            }
        });
    }
    
    protected override void CreateChildControls()
    {
        base.CreateChildControls();
        this.Title = "Custom Properties for Visual Webpart";
        Controls.Clear();
    
        this.pnlMain = new Panel();
        this.ddlList = new DropDownList();
        populateListDdl();
        ddlList.EnableViewState = true;
        pnlMain.Controls.Add(ddlList);
    
        //urlselector = new AssetUrlSelector();
        //pnlMain.Controls.Add(pnlMain);
        assettxt = new TextBox();
        assetbtn = new Button();
        assetlnk = new ScriptLink();
        assetlt = new Literal();
    
        assettxt.ID = "AssetTxt";
        assettxt.CssClass = "txtURL";
        assetlnk.Name = "AssetPickers.js";
        assetlnk.Localizable = true;
        assetlnk.Language = "javascript";
        assetbtn.Text = "Browse";
    
        pnlMain.Controls.Add(assetlnk);
        pnlMain.Controls.Add(assettxt);
        pnlMain.Controls.Add(assetbtn);
        string strRelativeWebURL = SPEncode.HtmlEncode(SPControl.GetContextWeb(Context).ServerRelativeUrl);
        if (strRelativeWebURL.Trim() == "/")
        {
            strRelativeWebURL = ""; 
        }
        string strAssetPickerConfig = string.Format(@"
                                                    <script type='text/javascript'>  
                                                    var element=document.getElementsByClassName('txtURL'); 
                                                    var id=element[0].id;                                                    
                                                    with(new AssetPickerConfig('testAssetPickerObj'))
                                                    {{
                                                         DefaultAssetImageLocation='';
                                                         CurrentWebBaseUrl='{0}';
                                                         OverrideDialogFeatures='';
                                                         OverrideDialogTitle='';
                                                         OverrideDialogDesc='';
                                                         OverrideDialogImageUrl='';
                                                         AssetUrlClientID=id;
                                                         AssetTextClientID='';                                                             
                                                         UseImageAssetPicker=true; //make this false to show Documents instead
                                                         DefaultToLastUsedLocation=true;
                                                         DisplayLookInSection=true;                                                             
                                                         ReturnCallback = null;}}
                                                        </script>",
                                                         strRelativeWebURL);
        assetlt.Text = strAssetPickerConfig;
        pnlMain.Controls.Add(assetlt);
    
        assetbtn.OnClientClick = "APD_LaunchAssetPickerUseConfigCurrentUrl('testAssetPickerObj'); return false;";
        this.Controls.Add(pnlMain);
    }
    
    protected override void RenderContents(System.Web.UI.HtmlTextWriter writer)
    {
        pnlMain.RenderControl(writer);
    }
    
    public override bool ApplyChanges()
    {
        EnsureChildControls();
        VWPWithCustomProperties vwp = WebPartToEdit as VWPWithCustomProperties;
        if (vwp == null)
            return false;
        vwp.List = this.ddlList.SelectedValue;
        return true;
    }
    
    public override void SyncChanges()
    {
        EnsureChildControls();
        VWPWithCustomProperties vwp = WebPartToEdit as VWPWithCustomProperties;
        if (vwp == null)
            return;
        populateListDdl();
        ddlList.SelectedValue = vwp.List;
    }
    

    } }

  4. Now, after pasting the above code to your HTMLEditor class file, paste the below code to your Usercontrol cs file: Assembly, Namespace

    protected override void OnInit(EventArgs e) { base.OnInit(e); InitializeControl(); }

    protected void Page_Load(object sender, EventArgs e)
    {          
    }
    
    EditorPartCollection IWebEditable.CreateEditorParts()
    {
        List<EditorPart> lists = new List<EditorPart>();
        lists.Add(new HtmlEditor());
        return new EditorPartCollection(lists);
    }
    
    object IWebEditable.WebBrowsableObject
    {
        get { return this; }
    }
    
    protected override void OnPreRender(EventArgs e)
    {
        # region "Code to fetch top 5 item from selected list and add it to label present in usercontrol"
        if (string.IsNullOrEmpty(List))
        {
            lblDisplay.InnerText = string.Empty;
        }
        else
        {
            try
            {
                lblDisplay.InnerText = string.Empty;
                using (SPSite site = new SPSite("http://win-8c97ll22qqc:100/sites/dev"))
                {
                    using (SPWeb web = site.OpenWeb())
                    {
                        SPList lst = web.Lists[List];
                        SPQuery query = new SPQuery();
                        query.Query = string.Concat("<Query><OrderBy><FieldRef Name='ID' Ascending='False' /></OrderBy></Query>");
                        query.ViewFields = string.Concat("<FieldRef Name='Title' />");
                        query.ViewFieldsOnly = true;
                        query.RowLimit = 5;
                        SPListItemCollection itemColl = lst.GetItems(query);
                        foreach (SPListItem item in itemColl)
                        {
                            if (item != null)
                                lblDisplay.InnerHtml += "<br/>" + item["Title"].ToString();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Custom Properties VWP", TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, ex.Message, ex.StackTrace);
            }
        }
        # endregion
    }
    

    } }

  5. Only label part is relevant as rest of markup will be automatically generated while adding visual webpart in your solution. Copy below code in UserControl markup file as given in image below: UserControl markup

  6. Build and deploy the soltution, and try to stick webpart on your sitepage. Will work like a charm!

-1

You can set attributes to customize the behavior of your Web Part. You can assign properties in the class how the following code:

[Category("Custom Properties")]
[DefaultValue(c_MyStringDefault)]
[WebPartStorage(Storage.Personal)]
[FriendlyNameAttribute("Custom String")]
[Description("Type a string value.")]
[Browsable(true)]
[XmlElement(ElementName="MyString")]
public string MyString
{
    get
    {
        return _myString;
    }
    set
    {
        _myString = value;
    }
}

In the following table describes each of types permitted in the web part properties

+---------------+-------------------------------+
| Property Type | Displayed in property pane as |
+---------------+-------------------------------+
| bool          | Check box                     |
| DateTime      | Text box                      |
| enum          | Dropdown                      |
| int           | Text box                      |
| string        | Text box                      |
+---------------+-------------------------------+

But

This default rendering by the framework does not allow for much customization because the user cannot get a handle to the controls that are rendered. For example, it has the following limitations: Control over UI: Numeric and string types are rendered as text boxes, enumeration types are rendered as a drop-down list box, and Boolean types are rendered as check boxes. So, you cannot show an enumeration type as radio buttons instead of a drop-down list box. Events: Events that are raised by the controls cannot be handled; for example, you cannot enable or disable a drop-down list based on selecting a check box. Validation: If user input has to be validated, the framework does not provide a way to easily attach a Microsoft ASP.NET validation control to the input control that is generated. For example, you cannot validate a string input for a valid email address through an ASP.NET RegEx validation control.

Source: http://msdn.microsoft.com/en-us/library/office/hh228018(v=office.14).aspx#SP14CustomWebPartEditor_Introduction

however

You can overcome these limitations by using custom editor parts. With custom editor parts, you can offer users functionality that can be achieved through ASP.NET user controls. A Web Part can implement custom editor parts that can be loaded when the Web Part is in edit mode, expose a custom UI, handle events, and validate inputs. A Web Part can have more than one custom editor part associated with it.

You can find a example code here, and more information of this it here

3
  • 1
    Please add an explanation to your answer. Link only answers tend to be less useful over time, as links eventually break.
    – Phil Greer
    Sep 24, 2014 at 21:21
  • ok thanks for your comment @PhilGreer :) , although the link that I insert in the answer is a link MSDN. Sep 24, 2014 at 21:29
  • MSDN links aren't immune to breaking over time. A brief explanation of the solution never hurts!
    – Phil Greer
    Sep 24, 2014 at 21:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.