页面上有一个Lookup field,当选择一个记录时,同时要把这个记录的其他值也带到本页面来,其中有好多是Lookup来的。

开始我用LinkEntity来取得它们的名字值,但是后来发现LinkEntity有数量限制,每条查询语句只能有10个LinkEntity,超过就报错,Advanced Find里也是一样的。

所以,用LinkEntity并不是一个好办法,而且我只是要取得一个名字的值而已,直觉告诉我不用那么麻烦的。

研究了一下,其实Fetchxml取的Lookup的值,不仅有GUID,名字的值也取到了,只不过名字值要经过一定的步骤转化才能拿到。

下面是具体方法:

首先,我们从返回的xml对象中取出我们的要的元素:

var county = oXmlDoc.getElementsByTagName("my_county")[0];

调用一个方法来取得名字值:

var countyName= GetAttributeName(county);

GetAttributeName方法,其实就是把字符串转化为Xml Node,再对里面的属性进行分析,得到我们要的那个属性的值:

function GetAttributeName(xmlNode) {
    var xmlStr = xmlNode.xml;
    var doc;
    if (window.ActiveXObject) {
      doc = new ActiveXObject('Microsoft.XMLDOM');
        doc.async = 'false';
        doc.loadXML(xmlStr);
    } else {
        var parser = new DOMParser();
        doc = parser.parseFromString(xmlStr, 'text/xml');
    }
    var name = doc.documentElement.attributes.getNamedItem("name").text;
    return name;
}

好的,这样Id和Name都有了,就可以给目标设值了。

posted @ 2012-05-28 12:58 Joy Zhong 阅读(1091) 评论(0) 编辑

这是一个非常普通的需求。

页面上有一个按钮,点击之后提交表单,如果什么都不管的话,用户可以在服务器响应完成之前再次点击,这样就出现了二次提交,后果可大可小。

那么我们应该防止二次点击,就要在用户点第一次之后马上Disable这个按钮。

具体:

按钮代码:

 <asp:Button ID="Button1" runat="server" UseSubmitBehavior="false"  
OnClick
="Button1_Click" Text="Button" OnClientClick="DisableButton(this)" />

Javascript:

 <script>
        function DisableButton(b) {
            b.disabled = true;
            b.value = 'Submitting';
          
        }

      
</script>

然后在后台代码里的Button1_Click事件里再做你想做的事情。

我们可以注意到这里是用OnClientClick的属性来调用Javascript从而实现Disable按钮的。开始的时候,我没有加入UseSubmitBehavior属性,就变成了点击按钮只执行客户端的代码,服务器端代码就不执行了。为了解决这个问题,加入了UseSubmitBehavior属性,并且要把他的值设为false。

为什么要设为false呢?简单来说,false表示不用客户端方法提交,则从服务器端提交,也就是执行OnClick的事件。反之,如果是true,则从客户端提交,忽略服务器端的事件。具体请看MSDN:http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.button.usesubmitbehavior.aspx

posted @ 2012-04-20 15:54 Joy Zhong 阅读(49) 评论(0) 编辑

需求:页面上有一个字段是Account类型的Lookup,另一个字段是Contact类型的Lookup。要求打开Contact lookup时只显示Account的Primary Contact的过滤视图。

分析:要做到这个功能,首先要重写(增加)Contact lookup的“显示查找视图”的事件;然后,在页面加载的时候就要把这个事件添加到Contact lookup上,在Account的值发生变化时也要做相应的改变,比如Account的值被清空的情况下,我们的自定义过滤视图就应该显示全部的Contact,所以这时要再次改写“显示查找视图”的事件。

 

步骤:

(1)

创建一个Javascript文件,上传到Webresource,并添加到Form Libraries。

代码:

oArg = {
    items: null,
    customViews: null,
    setCustomView: function (viewId, objectType, viewDisplayName, fetchXml, layoutXml) {
        customView = {
            recordType: objectType,
            id: viewId,
            name: viewDisplayName,
            fetchXml: fetchXml,
            layoutXml: layoutXml
        };
        this.customViews = new Array();
        this.customViews[0] = customView;
    },

    setLookupItems: function (ids, names, type) {
        var idArr = ids.split(';');
        var nameArr = names.split(';');
        this.items = new Array();
        for (var i = 0; i < idArr.length; i++) {
            if (idArr[i].length >= 32) {
                this.items[i] = {
                    oid: idArr[i],
                    outerText: nameArr[i],
                    oType: type,
                    getAttribute: function (value) {
                        switch (value) {
                            case 'oid':
                                {
                                    return this.oid;
                                }
                            case 'otype':
                                {
                                    return this.oType;
                                }
                            default:
                                {
                                    return null;
                                }
                        }
                    }
                };
            }
        }
    }
};

 

(2)

创建打开过滤视图的Javascript,添加到Form Libraries:

代码:

//Open filterd lookup view of contact base on Account
function OpenLookUpView() {
    
    var element = document.getElementById("contactid");//The contact lookup field id on the form
    var serverUrl = Xrm.Page.context.getServerUrl();
    var client = Xrm.Page.getAttribute("customerid").getValue();
    var viewId = "{00000000-0000-0000-0000-000000000001}"; // a dummy view ID 
    var objectType = 2; //contact
    var viewDisplayName = 'Client contact';
    if (client != null) {
        client = client[0].id;
        var fetchXml = "<fetch version='1.0' " +
                       "output-format='xml-platform' " +
                       "mapping='logical'>" +
                   "<entity name='contact'>" +
                   "<attribute name='fullname' />" +
                    "<attribute name='telephone1' />" +
                    "<attribute name='contactid' />" +
                    "<attribute name='emailaddress1' />" +
                    "<attribute name='address1_stateorprovince' />" +
                    "<attribute name='address1_county' />" +
                    "<attribute name='address1_city' />" +

                   "<order attribute='fullname' " +
                           "descending='false' />" +
                  "<link-entity name='account' from='primarycontactid' to='contactid' alias='ab'>" +
                   "<filter type='and'>" +

                       "<condition attribute='accountid' " +
                                   "operator='eq' " +
                                   "value='" + client + "' />" +

                   "</filter>" +
                   "</link-entity>" +

                   "</entity>" +
               "</fetch>";
        var layoutXml = "<grid name='resultset' " +
                             "object='1' " +
                             "jump='name' " +
                             "select='1' " +
                             "icon='1' " +
                             "preview='1'>" +
                         "<row name='result' " +
                              "id='contactid'>" +
                           "<cell name='fullname' " +
                                 "width='100' />" +

                            "<cell name='address1_city' " +
                            "width='80' />" +
                             "<cell name='address1_stateorprovince' " +
                            "width='80' />" +
                             "<cell name='address1_county' " +
                            "width='80' />" +
                           "<cell name='telephone1' " +
                                 "width='80' />" +
                            "<cell name='emailaddress1' " +
                            "width='100' />" +


                         "</row>" +
                       "</grid>";

        oArg.setCustomView(viewId, objectType, viewDisplayName, fetchXml, layoutXml);
        //Overwrite the lookup event to show custom filtered view
        element.onshowdialog = function (event) {
            var result = window.showModalDialog(serverUrl + '/_controls/lookup/lookupinfo.aspx?AllowFilterOff=1&DefaultType=' + objectType + '&DisableQuickFind=0&DisableViewPicker=0&LookupStyle=single&ShowNewButton=1&objecttypes=' + objectType + '&ShowPropButton=1&browse=0&DefaultViewId=' + viewId, oArg, 'dialogHeight:630px;dialogWidth:600px;resizable:yes;');
            event.oLookupItems = result;
        }




    }
    else {
        viewDisplayName = 'All contacts';
        var fetchXml = "<fetch version='1.0' " +
                       "output-format='xml-platform' " +
                       "mapping='logical'>" +
                   "<entity name='contact'>" +
                   "<attribute name='fullname' />" +
                    "<attribute name='telephone1' />" +
                    "<attribute name='contactid' />" +
                    "<attribute name='emailaddress1' />" +
                    "<attribute name='address1_stateorprovince' />" +
                    "<attribute name='address1_county' />" +
                    "<attribute name='address1_city' />" +

                   "<order attribute='fullname' " +
                           "descending='false' />" +


                   "</entity>" +
               "</fetch>";
        var layoutXml = "<grid name='resultset' " +
                             "object='1' " +
                             "jump='name' " +
                             "select='1' " +
                             "icon='1' " +
                             "preview='1'>" +
                         "<row name='result' " +
                              "id='contactid'>" +
                           "<cell name='fullname' " +
                                 "width='100' />" +

                            "<cell name='address1_city' " +
                            "width='80' />" +
                             "<cell name='address1_stateorprovince' " +
                            "width='80' />" +
                             "<cell name='address1_county' " +
                            "width='80' />" +
                           "<cell name='telephone1' " +
                                 "width='80' />" +
                            "<cell name='emailaddress1' " +
                            "width='100' />" +


                         "</row>" +
                       "</grid>";

        oArg.setCustomView(viewId, objectType, viewDisplayName, fetchXml, layoutXml);
        //Overwrite the lookup event to show custom filtered view
        element.onshowdialog = function (event) {
            var result = window.showModalDialog(serverUrl + '/_controls/lookup/lookupinfo.aspx?AllowFilterOff=1&DefaultType=' + objectType + '&DisableQuickFind=0&DisableViewPicker=0&LookupStyle=single&ShowNewButton=1&objecttypes=' + objectType + '&ShowPropButton=1&browse=0&DefaultViewId=' + viewId, oArg, 'dialogHeight:630px;dialogWidth:600px;resizable:yes;');
            event.oLookupItems = result;
        }

    }

}

(3)

在Form onload和Account onchange的event添加刚才我们加进来的library,Function填“OpenLookUpView”

好的。就是这样。

补充:

如果遇到这个错误:You do not have sufficient privileges to open this Lookup dialog box. 请检查一下objecttypecode对了没有。

如果自定义视图没有生效,请检查第(1)步的Javascript有没有添加到页面库中。

posted @ 2012-04-12 16:37 Joy Zhong 阅读(52) 评论(0) 编辑

之前接手这个项目的时候,看到的设计是这样的:

实体A的页面上有一个Lookup,连到实体B;

实体B的所有Fields都要展示到实体A;

实体A不能改动这些Fields;

实体B改动了这些Fields,也要体现到实体A;

在实体A重复创建和实体B一模一样的Fields……

这样的设计非常无聊,既然实体A要展示那些Fields,又不能改,其实只要直接拿实体B的信息即可,不需要重复创建Fields。

但是他们这样做是有原因的,因为CRM的sub grid展示形式很单一,无法达到用户的需要。

于是,现在,我改成了用Htm Web Resource来实现。

如图:

上图中的红框的信息全是来自“Property”这个Lookup的实体。

实现方法如下:

1. 创建一个Css,用来控制样式保持和CRM一致。我这里的名字是master.css,上传到CRM,(new_/Styles/master.css)

body { font-family:Tahoma; font-size:11px; color:393839; margin:0px; background-color:F6F8FA; border:0px; }
table
{font-size:11px;}
td
{padding: 5px 10px 3px 0px;}
h3
{font-size:12px;}

2. 上传sdk里的jquery到CRM(new_/Scripts/jquery1.4.1.min.js), jquery库可以在sdk找到:sdk\samplecode\js\restendpoint\jqueryrestdataoperations\jqueryrestdataoperations\scripts\jquery1.4.1.min.js

 

3. 创建Htm页面,上传到CRM(new_/PropertyInfo.htm),这里我省略部分方法只是重复的代码,大家要根据需要修改:

<HTML><HEAD><TITLE></TITLE> 
<SCRIPT src="../ClientGlobalContext.js.aspx"></SCRIPT>
<SCRIPT type=text/javascript src="Scripts/jquery1.4.1.min.js"></SCRIPT>
<SCRIPT type=text/javascript src="Scripts/sdk.metadata.js"></SCRIPT>
<LINK rel=stylesheet type=text/css href="Styles/master.css"></LINK>
<SCRIPT language=javascript>

var _serverUrl;
function retrievePropertyInfo() {

var customerAttribute = parent.Xrm.Page.data.entity.attributes.get("new_property");


if (customerAttribute != null) {


customerValue
= customerAttribute.getValue();


if (customerValue != null && customerValue[0] != null) {
var customerType = customerValue[0].typename;
var customerId = customerValue[0].id;
return retrieveRecord(customerId, "new_propertySet", retrieveCompleted, null);


}
}
}


function retrieveRecord(id, odataSetName, successCallback, errorCallback) {
var context = GetGlobalContext();
var serverUrl = context.getServerUrl();
_serverUrl
= serverUrl;

var odataEndPoint = "/XRMServices/2011/OrganizationData.svc";


if (!id) {
alert(
"record id is required.");
return;
}


if (!odataSetName) {
alert(
"odataSetName is required.");
return;
}


$.ajax({
type:
"GET",
contentType:
"application/json; charset=utf-8",
datatype:
"json",

url: serverUrl
+ odataEndPoint + "/" + odataSetName + "(guid'" + id + "')",
beforeSend:
function (XMLHttpRequest) {

XMLHttpRequest.setRequestHeader(
"Accept", "application/json");
},
success:
function (data, textStatus, XmlHttpRequest) {
if (successCallback) {
successCallback(data.d, textStatus, XmlHttpRequest);
}
},
error:
function (XmlHttpRequest, textStatus, errorThrown) {
if (errorCallback)
errorCallback(XmlHttpRequest, textStatus, errorThrown);
else
errorHandler(XmlHttpRequest, textStatus, errorThrown);
}
});
}


function retrieveCompleted(data, textStatus, XmlHttpRequest) {
/*Display the required fields and hide if the fields are null */
var entity = data;
    
//Picklist
var Type = (entity.new_Type.Value == null) ? "" : RetrieveOptionsetLabel("new_property", "new_type", entity.new_Type.Value, "type");
//Text
var AddressLine1 = (entity.new_AddressLine1 == null) ? "" : entity.new_AddressLine1;

if (addressline1 != "") {
document.getElementById(
"addressline1").innerHTML = AddressLine1;

}
//Hyperlink
var PortfolioName = (entity.new_Portfolio.Name == null) ? "" : entity.new_Portfolio.Name;
var PortfolioId = (entity.new_Portfolio.Id == null) ? "" : entity.new_Portfolio.Id;
if (portfolio != "") {
document.getElementById(
"portfolio").innerHTML =
"<a href='" + _serverUrl + "/main.aspx?etc=10014&id=%7b" + PortfolioId + "%7d&pagetype=entityrecord' target=_blank>" + PortfolioName + "</a>";


}




}


function RetrieveOptionsetLabel(entityName, optionSetName, optionSetValue, attributeId) {
// Entity schema name
var entityLogicalName = entityName;
// option set schema name
var RetrieveAttributeName = optionSetName;
// Target Field schema name to which optionset text needs to be assigned
var AssignAttributeName = attributeId;

// Option set value for which label needs to be retrieved
var stateValue = optionSetValue;

// Calling Metadata service to get Optionset Label
SDK.MetaData.RetrieveEntityAsync(SDK.MetaData.EntityFilters.Attributes,
entityLogicalName,
null,
false,
function (entityMetadata) {
successRetrieveEntity(entityLogicalName, entityMetadata, RetrieveAttributeName, stateValue, AssignAttributeName);
},
errorDisplay);


}

// Called upon successful metadata retrieval of the entity
function successRetrieveEntity(logicalName, entityMetadata, RetrieveAttributeName, OptionValue, AssignAttributeName) {
///<summary>
/// Retrieves attributes for the entity
///</summary>

var success = false;
for (var i = 0; i < entityMetadata.Attributes.length; i++) {
var AttributeMetadata = entityMetadata.Attributes[i];
if (success) break;
if (AttributeMetadata.SchemaName.toLowerCase() == RetrieveAttributeName.toLowerCase()) {
for (var o = 0; o < AttributeMetadata.OptionSet.Options.length; o++) {
var option = AttributeMetadata.OptionSet.Options[o];
if (option.OptionMetadata.Value == OptionValue) {
document.getElementById(AssignAttributeName).innerHTML
= option.OptionMetadata.Label.UserLocalizedLabel.Label;
success
= true;

break;
}
}
}

}


}

function errorDisplay(XmlHttpRequest, textStatus, errorThrown) {

alert(errorThrown);
}

</SCRIPT>


<META charset=utf-8></HEAD>
<BODY onload=retrievePropertyInfo() contentEditable=false>
<div id=propertyinfo>
<table style="width:100%">

<tbody>

<tr>
<td style="width:8%">Address Line 1</td>
<td id="addressline1" style="width:18%"></td>
<td style="width:8%">Type</td>
<td id="type" style="width:18%"></td>

<td style="width:8%">Asset ID</td>
<td id="assetid" style="width:18%"></td>
<td style="width:8%">Country</td>
<td id="country" style="width:auto"></td>

</tr>
<tr>
<td>Address Line 2</td>
<td id="addressline2"></td>


<td>Property Type</td>
<td id="propertytype"></td>

<td>Portfolio</td>
<td id="portfolio"></td>
<td>State/Province</td>
<td id="state"></td>
</tr>

<tr>

<td>Address Line 3</td>
<td id="addressline3"></td>
<td>Property SubType</td>
<td id="propertysubtype"></td>



<td>County</td>
<td id="county"></td>
<td>City</td>
<td id="city"></td>
</tr>

</tbody>
</table>
</div>

</BODY></HTML>


4. 将这个Htm Webresource插入我们需要它的地方,这样就可以了。

注意,我们的property lookup必须要在页面上才可以,设为不可见也行,因为如果它不在页面上,我们就拿不到它的id了,当然,通过别的方法拿到也是可以,但是就增加了不必要的麻烦。

 

补充,我们这里是用odata来取得数据的,写odata query的时候要注意。我是觉得很讨厌写这个query,所以我是用这个工具的:CRM 2011 OData Query Designer

如果我们是取一个实体的数据(
http://XXXX:8080/OOOOO/xrmservices/2011/OrganizationData.svc/odataSetName (guid'3653C6D5-2077-E111-920A-000C29139AA1')),那么返回的肯定是一个实体,则我们分析数据的时候只要用类似entity.fieldname 就可以拿到相应的值。

如果我们取得是多个实体的数据(http://XXXX:8080/OOOOO/xrmservices/2011/OrganizationData.svc/odataSetName?$select=new_Field1Name,new_new_entityB_new_entityA_entityBName/new_Field2Name$expand=new_new_entityB_new_entityA_entityBName&$filter=new_entityAId eq guid'3653C6D5-2077-E111-920A-000C29139AA1'),那么返回的是一个数组,我们分析数据的时候,对于a的数据要这样entity.results[0].field1name;对于b的数据则是:entity.results[0].new_new_entityB_new_entityA_entityBName.field2name

 

再补充:

如果取得是数据是Date,需要进行一下转换,odata返回的Date是这样的Date(1235764800000)

这样转换:

function ConvertTime(date) {
//This function use for convert the Date value get from odata, convert to javascript readable value
if (date == "") {
return "";
}
else {
var utcTime = parseInt(date.substr(6)); //date is like Date(1235764800000)
var result = new Date(utcTime);
result.setHours(result.getHours() + 8); //Database time is 8 hours late before local time
return result.format("M/dd/yyyy");
}
}


好的,基本上就是这样。

 

posted @ 2012-03-28 16:18 Joy Zhong 阅读(58) 评论(0) 编辑
function UserHasRole(roleName)
{
var serverUrl = Xrm.Page.context.getServerUrl();

var oDataEndpointUrl = serverUrl + "/XRMServices/2011/OrganizationData.svc/";
oDataEndpointUrl += "RoleSet?$top=1&$filter=Name eq '" + roleName + "'";

var service = GetRequestObject();

if (service != null)
{
service.open("GET", oDataEndpointUrl, false);
service.setRequestHeader("X-Requested-Width", "XMLHttpRequest");
service.setRequestHeader("Accept", "application/json, text/javascript, */*");
service.send(null);

var requestResults = eval('(' + service.responseText + ')').d;

if (requestResults != null && requestResults.results.length == 1)
{
var role = requestResults.results[0];

var id = role.RoleId;

var currentUserRoles = Xrm.Page.context.getUserRoles();

for (var i = 0; i < currentUserRoles.length; i++)
{
var userRole = currentUserRoles[i];

if (GuidsAreEqual(userRole, id))
{
return true;
}
}
}
}

return false;
}

function GetRequestObject()
{
if (window.XMLHttpRequest)
{
return new window.XMLHttpRequest;
}
else
{
try
{
return new ActiveXObject("MSXML2.XMLHTTP.3.0");
}
catch (ex)
{
return null;
}
}
}

function GuidsAreEqual(guid1, guid2)
{
var isEqual = false;

if (guid1 == null || guid2 == null)
{
isEqual = false;
}
else
{
isEqual = guid1.replace(/[{}]/g, "").toLowerCase() == guid2.replace(/[{}]/g, "").toLowerCase();
}

return isEqual;
}

应用:

var isManager=UserHasRole("Manager");
if(isManager)
{
//Do something
}
else
{
//Do something
}



posted @ 2012-03-09 12:33 Joy Zhong 阅读(20) 评论(0) 编辑
摘要: 很拗口的标题 -_-|||需求:页面上有两个同样的Field——accountnumber,想Disable其中一个,究竟为什么有这么傻叉的需求就不讨论了,只关注于如何实现。看似简单的问题,实际做的时候却遇到问题,一开始,当然是用“Xrm.Page.getControl("accountnumber").setDisabled(true);”,结果发现不行,只有排在前面的那个Field被Disable了,另一个还是enable的。为什么另一个不行呢?我用了曲折的方法debugging得到结论:function disablenumber() { debugger; //先取阅读全文
posted @ 2012-03-06 12:06 Joy Zhong 阅读(21) 评论(0) 编辑
摘要: using System;using System.Collections.Generic;using System.Linq;using System.Text;using Microsoft.Xrm.Sdk.Client;using Microsoft.Xrm.Sdk;using Microsoft.Xrm.Sdk.Query;using Microsoft.Xrm.Sdk.Messages;using Microsoft.Xrm.Sdk.Metadata;namespace MyNameSpace{ public class CrmService { priva...阅读全文
posted @ 2012-02-29 11:27 Joy Zhong 阅读(59) 评论(1) 编辑
摘要: 1.按姓氏笔画排序:Select * From TableName Order By CustomerName Collate Chinese_PRC_Stroke_ci_as //从少到多2.数据库加密:select encrypt('原始密码')select pwdencrypt('原始密码')select pwdcompare('原始密码','加密后密码') = 1--相同;否则不相同 encrypt('原始密码')select pwdencrypt('原始密码')select pwdcomp阅读全文
posted @ 2012-02-28 16:44 Joy Zhong 阅读(11) 评论(0) 编辑
摘要: SQL code一、基础1、说明:创建数据库CREATE DATABASE database-name 2、说明:删除数据库drop database dbname3、说明:备份sql server--- 创建 备份数据的 deviceUSE masterEXEC sp_addumpdevice 'disk', 'testBack', 'c:\mssql7backup\MyNwind_1.dat'--- 开始 备份BACKUP DATABASE pubs TO testBack 4、说明:创建新表create table tabname(col1阅读全文
posted @ 2012-02-28 16:43 Joy Zhong 阅读(14) 评论(0) 编辑
摘要: 请看这篇文章,按照他一步一步做,并根据自己的要求做些修改就可以了。MSCRM 2011: Filtered Lookup for "Add Existing..." Button of a CRM N:N View以防万一不能访问,这里把步骤大致说一下:1. 添加Javascript Webresource,不用添加到CRM的表内: function addExistingFromSubGridCustom(params) { var relName = params.gridControl.getParameter("relName"), ...阅读全文
posted @ 2012-01-11 15:47 Joy Zhong 阅读(88) 评论(0) 编辑