Question

Is there a way good way to replace a WebPart programmatically on a WikiPage and keep the old position? So far I'm able to delete a WebPart and add a new one but since it's a WikiPage where the current WebPart isn't in a specific zone (WebPart.Zone property is empty) I can't figure out how to replace the WebPart and keep the position on the site.

Code I'm using so far:

function 
Add-WebPartToPage($web, $page, $xmlReader, $zoneId, $zoneIndex, $marker)
{  
    $wpManager = $web.GetLimitedWebPartManager($page.Url, [System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared);

    $errorMsg = "";
    $wpGuid = [System.Guid]::NewGuid().ToString();
    $wpKey = "g_" + $wpGuid.Replace("-","_"); 

    $wpInstance = $wpManager.ImportWebPart($xmlReader, [ref]$errorMsg);    

    if([string]::IsNullOrEmpty($errorMsg))
    {
        $wpInstance.ID = $wpKey;
        $wpManager.AddWebPart($wpInstance, $zoneId, $zoneIndex);

        $oldContent = $page["WikiField"];
        $wpContent = '<div class="ms-rtestate-read ms-rte-wpbox" contenteditable="false"><div class="ms-rtestate-notify  ms-rtestate-read {0}" id="div_{0}" unselectable="on"></div><div id="vid_{0}" unselectable="on" style="display: none;"></div></div>' -f $wpGuid;
        $newContent = $oldContent.Replace($marker, $wpContent);
        $page["WikiField"] = $newContent;

        $page.Update();
    }
    else
    {
        Write-Host Error: $errorMsg;
    }   
}

function
Delete-WebPartFromPage($web, $page, $wpName)
{
    $wpManager = $web.GetLimitedWebPartManager($page.Url, [System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared);
    $webParts = $wpManager.WebParts
    foreach($wp in $($webParts))
    {
        if ($wp.Title.StartsWith($wpName))
        {
            $wpManager.DeleteWebPart($wp);
        }
    }
}
Était-ce utile?

La solution

Found a solution.

Since the old WebPart had its own div-element which was still in the page (even after deleting the WebPart with the SPLimitedWebPartManager) I was able to swap the IDs in the div without adding any extra HTML-code and thus keep the position.

Here's the updated Code (just the functionality, without error handling etc) if someone runs into the same problems or just needs guidance on how to add/remove/replace WebParts:

function Main-ReplaceWebPart(
[Parameter(Mandatory=$true)][string]$webUrl,
[Parameter(Mandatory=$true)][string]$wpName,
[Parameter(Mandatory=$true)][string]$pageTitle,
[Parameter(Mandatory=$true)][string]$listTitle,
[Parameter(Mandatory=$true)][string]$oldWpTitle)
{
    $web = Get-SPWeb $webUrl;       
    $xmlReader = Get-WebPartXmlReader $web $wpName;
    Replace-WebPart $web $wpName $xmlReader $pageTitle $listTitle $oldWpTitle
    $xmlReader.Close();
}

function 
Get-WebPartXmlReader($web, $wpName)
{
    $wpCatalog = $web.Site.GetCatalog([Microsoft.SharePoint.SPListTemplateType]::WebPartCatalog);
    $wp = $wpCatalog.Items | Where-Object {$_.Name -eq $wpName};
    $wpStream = $wp.File.OpenBinaryStream();
    $xmlReader = New-Object System.Xml.XmlTextReader($wpStream);
    return $xmlReader;
}

function
Replace-WebPart($web, $wpName, $xmlReader, $pageTitle, $listTitle, $oldWpTitle)
{
    $page = Get-SpPage $web $pageTitle $listTitle;
    $wpManager = $web.GetLimitedWebPartManager($page.Url, [System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared);
    $oldWpInfo = Delete-WebPartFromPage $web $page $oldWpTitle $wpManager;
    Add-WebPartToPage $web $page $xmlReader $oldWpInfo[0] $oldWpInfo[1] $oldWpInfo[2] $wpManager;
}

function 
Add-WebPartToPage($web, $page, $xmlReader, $zone, $zoneIndex, $oldWpId, $wpManager)
{  
    $errorMsg = "";
    $wpGuid = [System.Guid]::NewGuid().ToString();
    $wpKey = "g_" + $wpGuid.Replace("-","_"); 

    $wpInstance = $wpManager.ImportWebPart($xmlReader, [ref]$errorMsg);    

    if([string]::IsNullOrEmpty($errorMsg))
    {
        $wpInstance.ID = $wpKey;
        $wpManager.AddWebPart($wpInstance, $zone, $zoneIndex);

        $oldContent = $page["WikiField"];
        $newContent = $oldContent.Replace($oldWpId, $wpGuid);
        $page["WikiField"] = $newContent;

        $page.Update();
    }
    else
    {
        Write-Host Error: $errorMsg;
    }   
}

function
Delete-WebPartFromPage($web, $page, $wpName, $wpManager)
{
    $webParts = $wpManager.WebParts
    $index = 0;
    $zone = "WPZ"
    $wpId = "00"

    foreach($wp in $($webParts))
    {
        if ($wp.Title.StartsWith($wpName))
        {
            $index = $wp.ZoneIndex;
            $wpId = $wp.ID;
            if(![string]::IsNullOrEmpty($wp.Zone)){
                $zone = $wp.Zone;
            }

            $wpManager.DeleteWebPart($wp);
        }
    }
    $wpId = $wpId.substring(2).Replace('_','-');
    return $zone, $index, $wpId;
}

function 
Get-SpPage($web, $pageTitle, $listTitle)
{
    $list = $web.Lists[$listTitle];
    $spPage = $list.Items | Where-Object {$_.Name -eq $pageTitle};
    return $spPage;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à sharepoint.stackexchange
scroll top