Hello community!
I've wrapped a RadButton and RadContextMenu into a server user control and am trying to find out if it is possible to integrate the usercontrol with a RadGrid so that when a RadMenuItem is clicked it can fire the RadGrid_OnItemCommand event just like clicking on a RadButton would do...
My goal is to catch the server side click event of the RadMenuItem and invoke the click event of the RadButton, thereby fooling the RadGrid into using the CommandName and CommandArgument passed along in a CommandEventArgs object.
This is how the control is added to the HTML markup:
Here is a stripped down version of my user control that just does the basics:
Hopefully someone will have an insight for me, or if nothing else you can use what I have so far to some benefit...
Thanks!
Thad
PS: Here is the JavaScript. I didn't clean it up so it has a bit of functionality you don't notice above.
I've wrapped a RadButton and RadContextMenu into a server user control and am trying to find out if it is possible to integrate the usercontrol with a RadGrid so that when a RadMenuItem is clicked it can fire the RadGrid_OnItemCommand event just like clicking on a RadButton would do...
My goal is to catch the server side click event of the RadMenuItem and invoke the click event of the RadButton, thereby fooling the RadGrid into using the CommandName and CommandArgument passed along in a CommandEventArgs object.
This is how the control is added to the HTML markup:
<
telerik:GridTemplateColumn
HeaderText
=
"Actions"
HeaderStyle-Width
=
"125px"
ItemStyle-Width
=
"125px"
>
<
ItemTemplate
>
<
fmh:ActionButton
runat
=
"server"
CommandArgument='<%# Eval("FieldId") %>' ID="abGridTest"
OnMenuItemClicked="abGridTest_OnMenuItemClicked" >
<
ActionItems
>
<
fmh:ActionItem
Text
=
"Example 1"
Icon
=
"save"
CommandName
=
"test1"
/>
<
fmh:ActionItem
IsSeparator
=
"true"
/>
<
fmh:ActionItem
Text
=
"Example 2"
Icon
=
"edit"
CommandName
=
"test2"
/>
</
ActionItems
>
</
fmh:ActionButton
>
</
ItemTemplate
>
</
telerik:GridTemplateColumn
>
Here is a stripped down version of my user control that just does the basics:
public
class
ActionItem
{
public
ActionItem()
{
Visible =
true
;
}
public
bool
IsSeparator {
get
;
set
; }
public
bool
Visible {
get
;
set
; }
public
string
CommandName {
get
;
set
; }
public
string
Icon {
get
;
set
; }
public
string
Text {
get
;
set
; }
}
[ParseChildren(
true
)]
public
sealed
class
ActionButton : DataBoundControl, INamingContainer
{
[PersistenceMode(PersistenceMode.InnerProperty)]
[TemplateContainer(
typeof
(ActionButton))]
public
ITemplate ContentTemplate {
get
;
set
; }
[Bindable(
true
), DefaultValue(
""
)]
public
string
CommandArgument
{
get
{
object
o = ViewState[ClientID +
"_CommandArgument"
];
return
o ==
null
?
"0"
: o.ToString();
}
set
{ ViewState[ClientID +
"_CommandArgument"
] = value; }
}
[MergableProperty(
false
), PersistenceMode(PersistenceMode.InnerProperty), DefaultValue((
string
)
null
)]
public
Collection<ActionItem> ActionItems {
get
;
set
; }
public
event
CommandEventHandler MenuItemClicked;
public
RadContextMenu ContextMenu {
get
;
set
; }
public
RadButton Button {
get
;
set
; }
protected
override
void
CreateChildControls()
{
base
.CreateChildControls();
if
(ContentTemplate !=
null
)
ContentTemplate.InstantiateIn(
this
);
SetupButtonAndContextMenu();
if
(ActionItems !=
null
)
{
foreach
(ActionItem actionItem
in
ActionItems)
{
RadMenuItem rmi =
new
RadMenuItem();
SetupMenuItem(actionItem, rmi);
rmi.PostBack =
true
;
rmi.Visible = actionItem.Visible;
ContextMenu.Items.Add(rmi);
}
}
Controls.Add(Button);
Controls.Add(ContextMenu);
}
private
void
ContextMenuOnItemClick(
object
sender, RadMenuEventArgs radMenuEventArgs)
{
CommandEventArgs commandEventArgs =
new
CommandEventArgs(radMenuEventArgs.Item.Attributes[
"CommandName"
], CommandArgument);
// This is what I *thought* I would need to do, but this isn't working. Wrong binding flags?
//typeof (RadButton).InvokeMember("Click", BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, Button,
//
new
object
[] {commandEventArgs});
// This works just fine...because I have a reference to the event already
MenuItemClicked.Invoke(
this
,
new
CommandEventArgs(radMenuEventArgs.Item.Attributes[
"CommandName"
], CommandArgument));
}
private
void
SetupButtonAndContextMenu()
{
Button =
new
RadButton
{
ID =
"Button"
,
CssClass =
"Secondary Utility"
,
EnableSplitButton =
true
,
Text = @
"Action"
,
AutoPostBack =
false
,
OnClientClicked =
"$F.ActionButton.onClientClicked"
,
EnableEmbeddedSkins =
false
,
Skin =
"OurSkin"
,
Width = Width
};
Button.Icon.SecondaryIconUrl =
"/Common/Images/ButtonIcons/DropDownArrow.png"
;
ContextMenu =
new
RadContextMenu
{
ID =
"Button_Menu"
,
ExpandDelay = 0,
CollapseDelay = 0,
EnableEmbeddedSkins =
false
,
Skin =
"OurSkin"
,
OnClientItemClicked =
"$F.ActionButton.onClientMenuItemClicked"
};
ContextMenu.ItemClick += ContextMenuOnItemClick;
}
private
static
void
SetupMenuItem(ActionItem actionItem, RadMenuItem rmi)
{
if
(actionItem.IsSeparator)
{
rmi.IsSeparator =
true
;
return
;
}
if
(String.IsNullOrEmpty(actionItem.Text))
{
throw
new
ArgumentNullException(
"Text"
, @
"ActionItem.Text is a required argument."
);
}
rmi.Text = actionItem.Text;
if
(!String.IsNullOrEmpty(actionItem.Icon))
rmi.ImageUrl =
"/Common/Images/LinkButtonIcons/"
+ actionItem.Icon +
".png"
;
rmi.Attributes[
"CommandName"
] = !String.IsNullOrEmpty(actionItem.CommandName)
? actionItem.CommandName
: actionItem.Text.RemoveSpaces();
}
}
Hopefully someone will have an insight for me, or if nothing else you can use what I have so far to some benefit...
Thanks!
Thad
PS: Here is the JavaScript. I didn't clean it up so it has a bit of functionality you don't notice above.
$F.ActionButton = {
onClientClicked:
function
(sender, eventArgs) {
// Find the context menu and remove animations
var
contextMenu = window.$find(sender.get_id() +
'_Menu'
);
// Remove the animation so that it shows/hides immediately
contextMenu._slide._collapseAnimation.set_type(window.Telerik.Web.UI.AnimationType.None);
contextMenu._slide._expandAnimation.set_type(window.Telerik.Web.UI.AnimationType.None);
// If it is already visible, just hide it. For some reason the contextMenu.get_visible() returns false, hence the dom check.
if
(contextMenu.get_contextMenuElement().style.display ==
'block'
) {
contextMenu.hide();
return
;
}
// get the position of the Button that was clicked
var
currentLocation = window.$telerik.getBounds(sender.get_element());
// Calculate position to show the context menu
var
contextMenuLeft = currentLocation.x;
if
(contextMenu.get_attributes().getAttribute(
'RTL'
) ==
't'
) {
var
contextMenuWidth = $(
'#'
+ contextMenu.get_element().id +
'_detached'
).width();
if
(contextMenuWidth == 0) {
// reposition off screen so we can calculate the width. Can't do that until it has been rendered once.
contextMenu.showAt(-1000, -1000);
contextMenuWidth = $(
'#'
+ contextMenu.get_element().id +
'_detached'
).width();
}
contextMenuLeft = currentLocation.x + currentLocation.width - contextMenuWidth;
}
var
contextMenuTop = currentLocation.y + currentLocation.height;
// Show the context menu
contextMenu.showAt(contextMenuLeft, contextMenuTop);
},
onClientMenuItemClicked:
function
(sender, eventArgs) {
// Is there a function defined?
var
clientFunction = eventArgs.get_item().get_attributes().getAttribute(
"ClientFunction"
);
if
(!clientFunction || clientFunction.trim() ==
''
)
return
;
// Is this a real function?
var
fn = eval(clientFunction);
if
(!fn)
return
;
// Build arguments to pass including command name and command argument
var
args =
new
Object;
args.commandName = eventArgs.get_item().get_attributes().getAttribute(
"CommandName"
);
args.commandArgument = eventArgs.get_item().get_attributes().getAttribute(
"CommandArgument"
);
// Fire off the function passing arguments
fn(sender, args);
}