Displaying a context menu for Column Headers of an AspxGridView - asp.net

I read about the popup menu in the documentation here. I'm not clear as to whether this menu is already provided and we just have to enable a particular property to make it available? Or is it just an example of a popup menu and needs to be created? I've just begun exploring devexpress grids and any help would be appreciated.

This topic is devoted to the XtraGrid - the Winforms Grid. The ASPxGridView does not provide this menu, you may try to implement it yourself as it is shown in the
ASPxGridView - How to implement showing/hiding columns in the manner similar to ASPxPivotGrid
example.

It is possible we can create context menu on aspxgridview. Find the following example for aspxgridview context menu.
Default.aspx:
=============
<dx:ASPxGridView ID="grvContexMenuExample" runat="server" AutoGenerateColumns="false"
KeyFieldName="ID" EnableViewState="true" ClientInstanceName="grdtest" Width="100%"
Settings-GridLines="None" OnHtmlRowPrepared="grvContexMenuExample_HtmlRowPrepared">
<ClientSideEvents ContextMenu="function(s,e) {
if(e.objectType == 'header')
{
headerContextMenu.ShowAtPos(e.htmlEvent.clientX, e.htmlEvent.clientY);
}
else if(e.objectType == 'row')
{
headerContextMenu.ShowAtPos(e.htmlEvent.clientX, e.htmlEvent.clientY);
}
}" />
<Columns>
<%--Your columns goes here--%>
<columns>
</dx:ASPxGridView>
<!--Start New Context Menu !-->
<dx:ASPxPopupMenu ID="mnContextMenu" runat="server" ClientInstanceName="headerContextMenu"
EnableAnimation="false" PopupHorizontalAlign="OutsideRight" PopupVerticalAlign="TopSides"
PopupAction="RightMouseClick">
<Items>
<dx:MenuItem Text="New Context Menu1">
</dx:MenuItem>
</Items>
<ClientSideEvents ItemClick="ContextMenuItemClick" />
</dx:ASPxPopupMenu>
<!--End New Context Menu !-->
Default.aspx.cs:
================
protected void grvContexMenuExample_HtmlRowPrepared(object sender, ASPxGridViewTableRowEventArgs e)
{
if (e.RowType == GridViewRowType.Data)
if (e.RowType == GridViewRowType.Header)
{
e.Row.Attributes.Remove("oncontextmenu");
}
}

Related

ComboBox generate ICallbackEventHandler not found

Im using Devexpress ASP.NET AJAX ComboBox and trying to filter the result using callback events. This is the ASP markup for the ComboBox control
<dx:ASPxComboBox runat="server"
EnableViewState="false"
Width="100%" ID="Project"
ValueField="Value" TextField="Text"
CallbackPageSize="10"
EnableCallbackMode="true"
IncrementalFilteringMode="Contains"
OnItemsRequestedByFilterCondition="Project_ItemsRequestedByFilterCondition"
OnCallback="Project_Callback"
DropDownRows="10"
TextFormatString="{0} {1}">
<Columns>
<dx:ListBoxColumn Caption="Projekt" FieldName="Value" Name="value" />
<dx:ListBoxColumn Caption="Kund" FieldName="Text" Name="text" />
</Columns>
</dx:ASPxComboBox>
And here is the code behind
protected void Project_ItemsRequestedByFilterCondition(object source, DevExpress.Web.ListEditItemsRequestedByFilterConditionEventArgs e)
{
var data = handler.GetProjectList(e.Filter);
Project.DataSource = data;
Project.DataBind();
}
protected void Project_Callback(object sender, DevExpress.Web.CallbackEventArgsBase e)
{
}
Every time i try to write in the combobox the page says that the IEventCallBackHandler is not found. Please see the attached image.
I found the problem. The page is inherit our own base class that has a custom implementation of FindControl.

DevXpress grid view: change GridViewCommandColumnCustomButton Image-Url

all.
I have a DevXpress gridview, and each row contains 2 custom image buttons: edit and cancel.
In the grid is a specific column that will determine whether the image buttons get displayed or not. If the column contains a 5, then don't show the buttons. Otherwise always show the buttons.
How can I access the Image-Url property from the code behind or will it have to be through the JavaScript?
Code extract re custom button definition:
<dxwgv:GridViewCommandColumn ButtonType="Image" Caption="Edit" AllowDragDrop="False" >
<CustomButtons>
<dxwgv:GridViewCommandColumnCustomButton ID="EditButton" Text="Click to edit" Image-Url="~/Images/16x16/edit.png" Visibility="AllDataRows" Image-AlternateText="Edit" />
</CustomButtons>
</dxwgv:GridViewCommandColumn>
<dxwgv:GridViewCommandColumn ButtonType="Image" Caption="Cancel" AllowDragDrop="False">
<CustomButtons>
<dxwgv:GridViewCommandColumnCustomButton ID="CancelButton" Text="Click to cancel" Image-Url="~/Images/16x16/delete2.png" Visibility="AllDataRows" Image-AlternateText="Cancel" />
</CustomButtons>
</dxwgv:GridViewCommandColumn>
Any ideas would be appreciated. Really not have much joy with DevXpress.
Thanks!
Here is one possibility:
protected void ASPxGridView1_CustomButtonInitialize(object sender, ASPxGridViewCustomButtonEventArgs e)
{
int i = Convert.ToInt32((sender as ASPxGridView).GetMasterRowKeyValue());
if (i == 5)
e.Image.Url = "images/checkmark.gif";
else
e.Image.Url = "images/trash.gif";
}
Then of course in the ASPX file you would need to add:
oncustombuttoninitialize="ASPxGridView1_CustomButtonInitialize"

ASPxGridView - How to get the Selected Row in a Detail Grid of a Master-Detail GridView?

Can anyone explan how I can access the selected row of a detail grid in a DevExpress master-detail ASPxGridView? I've found an example on the devexpress support website But I can't get it tow ork, I'm working with version 11 of DevExpress.
Thanks in advance.
I found a way to get the selected row of the detail grid, not sure how 'advised' it is to do it this way but it works fine for me, I added an onload() event to the detail grid and then I was able to access that instance of the gridview by casting it to an ASPxGridView.
Here is my Code, the detail grid:
<Templates>
<DetailRow>
<dx:ASPxGridView ID="detailGrid" runat="server" DataSourceID="SqlDataSource2"
Width="100%" OnBeforePerformDataSelect="detailGrid_DataSelect"
KeyFieldName="InvoiceID"
EnableCallBacks="False"
onload="detailGrid_Load"
>
and then I handle the onoad() event like this:
ASPxGridView gridView;
protected void detailGrid_Load(object sender, EventArgs e)
{
gridView = sender as ASPxGridView;
gridView.SelectionChanged += new EventHandler(gridView_SelectionChanged);
}
So I just made a ASPxGridView instance of the detail grid, and now I can make use of its SelectionChanged() event.
private static int invoiceID;
void gridView_SelectionChanged(object sender, EventArgs e)
{
invoiceID = Convert.ToInt64(gridView.GetSelectedFieldValues("InvoiceID")[0]);
}
Thanks in advance to user189756 answer because it is helpful but I suppose many people are heading into the same issue here and because the previous answer is not up to date for current versions of DevExpress Asp.Net WebForms since it was written almost 5 years ago I just wanted to add an important point here.
In order to process the Selection Event on server side now you must specify it in ASPxGridView attributes as follows:
<dx:ASPxGridView ID="MainGrid" runat="server">
<Columns>
<!-- Grid Columns here -->
</Columns>
<Templates>
<DetailRow>
<dx:ASPxGridView ID="DetailGrid" runat="server" KeyFieldName="ID" OnInit="Grid_Init" OnSelectionChanged="Grid_SelectionChanged">
<Columns>
<!-- Grid Columns here -->
</Columns>
<!-- Now the following code is relevant to process Selection Event on Server Side-->
<SettingsBehavior AllowFocusedRow="true"
AllowSelectByRowClick="true"
ProcessFocusedRowChangedOnServer="true"
ProcessSelectionChangedOnServer="true"/>
<SettingsDetail IsDetailGrid="True" />
</dx:ASPxGridView>
</DetailRow>
</Templates>
<SettingsDetail ShowDetailRow="True" />
</dx:ASPxGridView>
Notice I used the row selection by click but there is also another variant using checkboxes. So now the only thing you have to do is implement Selection Event Handler in code behind.
protected void Grid_SelectionChanged(object sender, EventArgs e)
{
ASPxGridView grid = sender as ASPxGridView;
for (int i = 0; i < grid.VisibleRowCount; i++) // Loop through selected rows
{
if (grid.Selection.IsRowSelected(i)) // do whatever you need to do with selected row values
{
// now use pre-initialized List<object> selectedList to save
selectedList.Add(Convert.ToInt32(grid.GetRowValues(i, "ID")));
}
}
ViewState["SelectedList"] = selectedList;
}

How to programmatically reach any AspxControl inside an AspXGridView's EditItemTemplate

Its very simple and i feel myself as an idiot :(
I newly started to using DevX Controls. Its documentation and sample projects are SUCKS!
My problem is:
I have an ASPxGridView on my aspx page:
<dx:ASPxGridView ID="dxdgMyGrid" runat="server" AutoGenerateColumns="False" OnStartRowEditing="DxGridStartRowEditing">
<SettingsEditing Mode="PopupEditForm" PopupEditFormHeight="200px" PopupEditFormWidth="500px"
EditFormColumnCount="2" PopupEditFormHorizontalAlign="Center" PopupEditFormVerticalAlign="Middle"
PopupEditFormModal="true" />
<Columns>
<dx:GridViewDataTextColumn FieldName="MyField1" VisibleIndex="1">
<EditFormSettings VisibleIndex="0" />
<EditItemTemplate>
<dx:ASPxDateEdit ID="dxdateMyField1" runat="server">
</dx:ASPxDateEdit>
</EditItemTemplate>
</dx:GridViewDataTextColumn>
<dx:GridViewDataColumn FieldName="MyField2" VisibleIndex="4">
<EditFormSettings VisibleIndex="1" />
<EditItemTemplate>
<dx:ASPxComboBox ID="dxcomboMyField2" runat="server">
</dx:ASPxComboBox>
</EditItemTemplate>
</dx:GridViewDataColumn>
</Columns>
How can i reach dxdateMyField1 or dxcomboMyfield2 on ASPX.CS file? I want to write:
dxcomboMyField2.DataSource = GetMyData2List();
dxcomboMyField2.SelectedItemIndex = 0;
... etc.
Thanks a lot.
You cannot access the EditItemTemplate Control Directly. You can access them at the HtmlRowCreated event as:
if (e.RowType != GridViewRowType.InlineEdit) return;
ASPxTextBox txtBox = ASPxGridView1.FindEditRowCellTemplateControl(ASPxGridView1.Columns["Name"]
as GridViewDataColumn, "ASPxTextBox1") as ASPxTextBox;
Check the documentation on Accessing Controls Contained within Templates
It is possible to cast the ASPxLabel.NamingContainer property to GridViewEditItemTemplateContainer and get a column value via the GridViewEditItemTemplateContainer.Text property.
But I like the technique of using the Init/Load event handler.When the grid switches to edit mode, the ASPxLabel.Load event is raised. Check this article The general technique of using the Init/Load event handler for implementation help.
[ASPx]
<dxe:ASPxTextBox ID="txtName" runat="server" Width="170px" OnInit="txtName_Init">
</dxe:ASPxTextBox>
[C#]
ASPxTextBox txtName;
protected void txtName_Init(object sender, EventArgs e)
{
txtName = (ASPxTextBox)sender;
GridViewEditFormTemplateContainer container = txtName.NamingContainer as GridViewEditFormTemplateContainer;
// You can remove the if statement, and try to insert a new record. You'll catch an exception, because the DataBinder returns null reference
if (!container.Grid.IsNewRowEditing)
txtName.Text = DataBinder.Eval(container.DataItem, "CategoryName").ToString();
}
Update Event:
protected void grid_RowUpdating(object sender, DevExpress.Web.Data.ASPxDataUpdatingEventArgs e)
{
e.NewValues["CategoryName"] = txtName.Text;
}
There is already an question - ASPxGridView - How to find a control inside the EditItemTemplate on DevExpress fourm .
You can use combo box init/load event handler for setting combo datasource. If that doesn't work for you, use FindEditRowCellTemplateControl (use link in comments for further explanation).

lazy loading asp.net Ajax Control Toolkit accordion

I am using the asp.net Ajax Control Toolkit accordion (http://www.asp.net/ajaxlibrary/act_Accordion.ashx) and each accordion pane contains quite a lof information.
All that info is generated in the page but it is not shown because the toolkit gives the non active panes a
(style="display:none;)
But because the info is in the page, it becomes a very heavy page to load.
I am looking for a way to load the panes on-demand: so only if the user clicks the pane an ajax request is send and the pane is loaded and expanded.
Can this be done with this control or should i choose a different accordion? Any help or suggestions appreciated.
update
Currently the Accordion is created with two, nested, repeaters. The first repeater loops over the categories and creates a panel for each category. The second repeater repeates inside each panel takes the content for one category and creates the content of the panel.
Pleun
I don't have the points to comment and ask you questions. Sorry. :(
My questions are in regard to how you plan to create and populate the Accordion.
Will you create panes by hand using markup in the IDE or will you bind the Accordion to a DataSource that will dynamically create the panes you need?
Will you have 3 separate DataSources or a different combination of the following:
1.) DataSource to initialize the number of panels and populate only the panel's Header information.
2.) DataSource to populate the Static Content of all panels on first load.
3.) DataSource to populate the Lazy-Loaded Content of a single panel the user clicks to expand.
With your answers I hope to update this answer with a real one. Thanks.
Update: This is achievable with the Ajax Control Toolkit's Accordion.
I have some very basic code below as proof of concept. It could be smoother, but I'll leave it up to you to add a "Loading" image using the UpdatingProgress control if you find it necessary.
The Accordion in the Aspx markup:
(Notice the UpdatePanels - you can replace them with callbacks if you want, I just wanted to keep the answer simple)
<asp:Accordion ID="acc_Accordion" runat="server" RequireOpenedPane="false"
SelectedIndex="-1" onitemcommand="acc_Accordion_ItemCommand" >
<HeaderTemplate>
<asp:UpdatePanel ID="up_UpdateHeader" runat="server">
<ContentTemplate>
<%--When using "Eval" inside strings for Asp.net controls,
you MUST wrap them in apostrophes ('),
otherwise with (") you will get parser errors!--%>
<asp:LinkButton ID="btn_Header" runat="server"
Text='<%# Eval("HeaderText") %>'
CommandName="UpdatePane" CommandArgument='<%# Eval("ItemID") %>'
Font-Underline="false" ForeColor="Black"
style="width:100%; height:100%; cursor:pointer;"/>
<%--Use Cursor:Pointer to keep a consistent
interface after disabling the button.--%>
</ContentTemplate>
</asp:UpdatePanel>
</HeaderTemplate>
<ContentTemplate>
<asp:UpdatePanel ID="up_UpdateContent" runat="server"
UpdateMode="Conditional">
<ContentTemplate>
<%# Eval("ContentText")%>
<asp:Label ID="lbl_Content" runat="server"
Text="<%# DateTime.Now.ToLongTimeString() %>"></asp:Label>
</ContentTemplate>
</asp:UpdatePanel>
</ContentTemplate>
</asp:Accordion>
The Page_Load() - Prep our "dummy" data:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack == false)
{
DataTable dt = new DataTable();
dt.Columns.Add("ItemID");
dt.Columns.Add("HeaderText");
dt.Columns.Add("ContentText");
dt.Rows.Add(new object[] { 123456, "Header 1", "Content A." });
dt.Rows.Add(new object[] { 654321, "Header 2", "Content B." });
acc_Accordion.DataSource = new System.Data.DataTableReader(dt);
acc_Accordion.DataBind();
}
}
The ItemCommand() - This captures button-clicks inside the Accordion:
protected void acc_Accordion_ItemCommand(object sender, CommandEventArgs e)
{
if (e.CommandName == "UpdatePane")
{
AjaxControlToolkit.AccordionContentPanel acp
= (e as AjaxControlToolkit.AccordionCommandEventArgs).Container;
UpdatePanel upHeader
= acc_Accordion.Panes[acp.DisplayIndex].HeaderContainer
.Controls.OfType<Control>()
.Single(c => c is UpdatePanel) as UpdatePanel;
LinkButton btn
= upHeader.ContentTemplateContainer
.Controls.OfType<Control>()
.Single(b => b is LinkButton) as LinkButton;
UpdatePanel upContent
= acc_Accordion.Panes[acp.DisplayIndex].ContentContainer
.Controls.OfType<Control>()
.Single(c => c is UpdatePanel) as UpdatePanel;
Label lbl
= upContent.ContentTemplateContainer
.Controls.OfType<Control>()
.Single(c => c is Label) as Label;
lbl.Text = " ID: " + e.CommandArgument
+ " and Time: " + DateTime.Now.ToLongTimeString();
//You can use the ID from e.CommandArgument to query the database
// for data to update your Repeaters with.
btn.Enabled = false;//Disabling the button for our Header
// will prevent Asyncronous Postbacks to update the content again.
//Only disable this if you don't need to update the content
// when the user clicks to view the pane again.
upContent.Update();//Set UpdateMode="Conditional".
}
}
I know this looks like a lot, but it's only a few lines of code (before wrapping and commenting).
Tip 4 in 6 Tips for Working with the ASP.NET AJAX Accordion Control explains how to determine when the selected index has changed. From the JavaScript event handler you can do whatever you want to update the content of the newly-selected accordion pane (call a web service, use an update panel, etc.)
Combining this with another article explaining how to use an update panel to refesh content when a tab page is selected for a simple demo:
<ajaxToolKit:Accordion ID="accSample" runat="server"
RequireOpenedPane="false" SelectedIndex="-1">
<Panes>
<ajaxToolKit:AccordionPane runat="server">
<Header>Sample</Header>
<Content>
<asp:Button ID="btnSample" runat="server" OnClick="OnShowSample" Style="display: none" />
<script type="text/javascript">
Sys.Application.add_load(function (sender, args) {
if (!args.get_isPartialLoad()) {
var accSample = $find('<%= accSample.ClientID %>_AccordionExtender');
accSample.add_selectedIndexChanged(function (sender, eventArgs) {
$get('<%= btnSample.ClientID %>').click();
});
}
});
</script>
<asp:UpdatePanel ID="upSample" runat="server">
<ContentTemplate>
<asp:DataGrid ID="dgSample" runat="server" Visible="false"/>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="btnSample" />
</Triggers>
</asp:UpdatePanel>
</Content>
</ajaxToolKit:AccordionPane>
</Panes>
</ajaxToolKit:Accordion>
then in code-behind
protected void OnShowSample(object sender, EventArgs e)
{
dgSample.DataSource = new string[] { "test" };
dgSample.DataBind();
dgSample.Visible = true;
}
Take a look at the ASPxNavBar control (a part of the free ASPxperience Suite) from DevExpress. If the ASPxNavBar’s EnableCallBacks property is set to true, contents of collapsed groups are not represented on the client side. When a group is expanded for the first time, its content is retrieved from the server and then cached on the client. The next time the group is expanded, its content is taken from the client and no callback to the server is performed.
Review the ASPxNavBar - Callbacks (AJAX) Online Demo for more information.
All I can suggest to you is add linkButtons to your headers and panels to your panes:
<Panes>
<asp:AccordionPane ID="First" runat="server">
<Header>
<asp:LinkButton CommandName="ASD2" ID="LinkButton2" runat="server">LinkButton</asp:LinkButton>
</Header>
<Content>
<asp:Panel ID="Panel2" runat="server" Visible="true">
First
</asp:Panel>
</Content>
</asp:AccordionPane>
<asp:AccordionPane ID="Second" runat="server">
<Header>
<asp:LinkButton CommandName="ASD" ID="LinkButton1" runat="server">LinkButton</asp:LinkButton>
</Header>
<Content>
<asp:Panel ID="Panel1" runat="server" Visible="false">
Second
</asp:Panel>
</Content>
</asp:AccordionPane>
</Panes>
and in the Accordion1_ItemCommand set the Visible property of corresponding panel.
protected void Accordion1_ItemCommand(object sender, CommandEventArgs e)

Resources