I have a web form in which i want to show label with time in decreasing fashion from 180 second to zero,i am using following code.
<div>
<asp:ScriptManager ID="SM1" runat="server"></asp:ScriptManager>
<asp:Timer ID="timer1" runat="server" Interval="1000"
OnTick="timer1_tick">
</asp:Timer>
</div>
<div>
<asp:UpdatePanel ID="updPnl" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:Label ID="lblTimer" runat="server"></asp:Label>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="timer1" EventName="tick" />
</Triggers>
</asp:UpdatePanel>
</div>
and code behind
protected void timer1_tick(object sender, EventArgs e)
{
if (0 > DateTime.Compare(DateTime.Now,
DateTime.Parse(Session["TimeCount"].ToString())))
{
lblTimer.Text = "Number of Second Left: " +
((Int32)DateTime.Parse(Session["TimeCount"].
ToString()).Subtract(DateTime.Now).TotalSeconds).ToString();
}
else
{
}
}
and page load
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
Page.Header.Title = "Test";
NewRecord();
}
if (!SM1.IsInAsyncPostBack)
Session["TimeCount"] = DateTime.Now.AddSeconds(180).ToString();
}
problem is that counter refresh each time to 180 when user click on button,and label is static value like 177,173 etc,i want to show changing in counting is shown to user?it is basically Q/A software.
Related
I want to add a toolbar inside website, the toolbar change inside component on each page. For now, I have this but I want my toolbar to be like this. How could i make this toolbar to update depend on the page the user go ?
The toolbar would be in the MainLayout and need to change content with a switch (not the best option I think) or is it possible to give new content to MainLayout from the page content ?
This is the code for the banner component :
<div class="extend-space" style="left:#($"-{Convert.ToInt32(offsetX)}px")">
<div class="banner" style="left:#(Convert.ToInt32(offsetX)+"px");width:#(Convert.ToInt32(width)+"px");">
<div class="banner-title">
#if (Icon != null)
{<i id="banner-title-icon" class="icon fas fa-#Icon"></i>}
<h3 class="title">#Title</h3>
</div>
<div class="toolbar">
<span id="arrow-left" class="scrollable" onclick="lastTool()">
<i class="fas fa-angle-left arrow"></i>
</span>
<span id="toolbar">
#ChildContent
</span>
<span id="arrow-right" class="scrollable" onclick="nextTool()">
<i class="fas fa-angle-right arrow"></i>
</span>
</div>
</div>
ChildContent should be a list of buttons with function onclick on it so this is the part that need to update on each page.
I add an example of how I use it on a page :
<XLBanner Title="Catégories" Icon="sitemap">
<XLButton Icon="plus" Content="#SharedLocalizer["Add"]" OnClickFunction="#AddCategorie" />
<XLButton Icon="save" Content="#SharedLocalizer["Save"]" OnClickFunction="#Save" disabled="#(!UnsavedChanges)" />
<XLButton Icon="redo" Content="#SharedLocalizer["Reset"]" OnClickFunction="#DeleteUnsavedChanges" disabled="#(SelectedCategorie == null)" />
<XLButton Icon="trash-alt" Content="#SharedLocalizer["Remove"]" OnClickFunction="#SuppCategorie" disabled="#(SelectedCategorie == null)" />
<XLButton Icon="copy" Content="#SharedLocalizer["Copy"]" OnClickFunction="#CopyCategorie" disabled="#(SelectedCategorie == null)" />
<XLButton Icon="download" Content="#SharedLocalizer["Export"]" OnClickFunction="#Export" /
</XLBanner>
What would be needed to update is the XLButton and the OnClickFunction.
My banner has differents tools depend on the page exemple dashboard page, exemple categorie page
If I understand the question correctly a version of this should work for you.
Basically:
Create a simple service that holds the menu data and has an event that is raised whenever the menu data changes and register it.
Use a DynamicComponent in Layout that plugs into the service.
Trigger StateHasChanged on the Layout whenever the service raises a menu change event.
Set the menu you want in each page in OnInitialized.
Two "Menus" to work with:
Menu1.razor
<h3>Menu1</h3>
Menu2.razor
<h3>Menu2</h3>
A simple LayoutService
public class LayoutService
{
public Type MenuControl { get; private set; } = typeof(Menu1);
public Dictionary<string, object>? MenuParameters { get; private set; }
public event EventHandler? MenuChanged;
public void ChangeMenu(Type menu)
{
this.MenuControl = menu;
MenuChanged?.Invoke(this, EventArgs.Empty);
}
public void ChangeMenu(Type menu, Dictionary<string, object> parameters)
{
this.MenuParameters = parameters;
this.MenuControl = menu;
MenuChanged?.Invoke(this, EventArgs.Empty);
}
}
registered in Program.cs:
builder.Services.AddScoped<LayoutService>();
MainLayout.razor
#inherits LayoutComponentBase
#inject LayoutService LayoutService;
#implements IDisposable
<PageTitle>BlazorApp1</PageTitle>
<DynamicComponent Type=this.LayoutService.MenuControl Parameters=this.LayoutService.MenuParameters />
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main>
<div class="top-row px-4">
About
</div>
<article class="content px-4">
#Body
</article>
</main>
</div>
#code {
protected override void OnInitialized()
=> this.LayoutService.MenuChanged += this.MenuChanged;
private void MenuChanged(object? sender, EventArgs e)
=> this.InvokeAsync(StateHasChanged);
public void Dispose()
=> this.LayoutService.MenuChanged -= this.MenuChanged;
}
And example page:
#page "/"
#inject LayoutService LayoutService
Page Content
#code {
protected override void OnInitialized()
{
this.LayoutService.ChangeMenu(typeof(Menu1));
}
Don't get too focused on the layout as a single entity that you have to use for every page in the whole site. You can have as many Layout components as you want, and you can nest them just like you would with any class and derived class.
https://blazor-university.com/layouts/nested-layouts/
Issue Summary:
The processing logic on my new screen is working but the page doesn't show any feedback to the user (e.g. Timer doesn't show, No Red/Green checkboxes, checkboxes aren't disabled)
Issue Detail:
I'm creating a processing screen that requires separate information from the user to be used by the processing delegate. The business logic works, but the user experience isn't like other processing screens. When you click Process there is nothing shown to the user. Normally the page refreshes the grid by disabling and showing only the selected items being processed, in addition to the long operation timer being added (then replaced by a green check or red x based on whether the process was successful or failed). When I click process all the entire grid's selected column is checked, but again nothing else changes (e.g. no timer, status, nor is the grid disabled). Ultimately both process and process all perform the business logic but the user doesn't see anything to indicate said success/failure.
The screen shows all customer locations because the process is updating some statistics that we are keeping for each location based on orders that exist for each location.
My Graph
public class CalculateLocationStatsProcess : PXGraph<CalculateLocationStatsProcess>
{
public PXCancel<LocationStatsFilter> Cancel;
public PXFilter<LocationStatsFilter> filterLocStat;
public PXFilteredProcessingJoin<Location,
LocationStatsFilter,
InnerJoin<Customer, On<Customer.bAccountID, Equal<Location.bAccountID>>>,
Where<True, Equal<True>>,
OrderBy<Asc<Customer.acctCD, Asc<Location.locationCD>>>> processLocations;
public CalculateLocationStatsProcess()
{
}
public virtual void LocationStatsFilter_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
processLocations.SetProcessDelegate(
delegate (List<Location> list)
{
var newList = new List<Location>();
foreach (Location locLp in list)
{
newList.Add(locLp);
}
CalculateLocationStatsProcess.updateLocationStats(newList, filterLocStat.Current);
}
);
}
public static void updateLocationStats(List<Location> locations, LocationStatsFilter filter)
{
var graph = new PXGraph();
var locStats = new StatsHelper(graph, filter.TargetDate);
bool erred = false;
for (int iLp = 0; iLp < locations.Count; iLp++)
{
Location locationLp = locations[iLp];
PXProcessing<Location>.SetCurrentItem(locationLp);
try
{
locStats.setCommStats(locationLp);
}
catch (Exception ex)
{
erred = true;
PXProcessing<Location>.SetError(iLp, ex.Message);
}
}
locStats.StatCache.Persist(PXDBOperation.Insert);
locStats.StatCache.Persist(PXDBOperation.Update);
if (erred)
{
throw new PXException("Location(s) failed during recalculation process. View individual lines to see their specific error.");
}
}
}
My Page
<%# Page Language="C#" MasterPageFile="~/MasterPages/FormDetail.master" AutoEventWireup="true" ValidateRequest="false" CodeFile="SO509503.aspx.cs" Inherits="Page_SO509503" Title="Calculate Location Stats" %>
<%# MasterType VirtualPath="~/MasterPages/FormDetail.master" %>
<asp:Content ID="cont1" ContentPlaceHolderID="phDS" runat="Server">
<px:PXDataSource ID="ds" runat="server" Visible="True" Width="100%" PrimaryView="filterLocStat" TypeName="exampleNS.CalculateLocationStatsProcess">
<CallbackCommands>
</CallbackCommands>
</px:PXDataSource>
</asp:Content>
<asp:Content ID="cont2" ContentPlaceHolderID="phF" runat="Server">
<px:PXFormView ID="formFilter" runat="server" DataMember="filterLocStat" DataSourceID="ds" Style="z-index: 100" Width="100%" >
<Template>
<px:PXLayoutRule runat="server" ID="PXLayoutRule1" ControlSize="M" LabelsWidth="M" StartRow="true" />
<px:PXDateTimeEdit runat="server" ID="edTargetDate" DataField="TargetDate" />
</Template>
</px:PXFormView>
</asp:Content>
<asp:Content ID="cont3" ContentPlaceHolderID="phG" runat="Server">
<px:PXGrid ID="gridLocations" runat="server"
AdjustPageSize="Auto" AllowPaging="True" AllowSearch="true" DataSourceID="ds" FilesIndicator="false"
Height="400px" NoteIndicator="false" SkinID="Inquire" Style="z-index: 100" SyncPosition="true" Width="100%" >
<AutoSize Container="Window" Enabled="True" MinHeight="200" />
<Levels>
<px:PXGridLevel DataMember="processLocations">
<Columns>
<px:PXGridColumn DataField="Selected" Type="CheckBox" AllowCheckAll="true" Width="40px" />
<px:PXGridColumn DataField="Customer__AcctCD" Width="125px" />
<px:PXGridColumn DataField="LocationCD" Width="75px" />
<px:PXGridColumn DataField="Descr" Width="175px" />
</Columns>
</px:PXGridLevel>
</Levels>
</px:PXGrid>
</asp:Content>
My Filter DAC
public class LocationStatsFilter : IBqlTable
{
#region TargetDate
public abstract class targetDate : IBqlField { }
[PXDate()]
[PXUIField(DisplayName = "Target Month and Year")]
public virtual DateTime? TargetDate { get; set; }
#endregion
}
My Location Extension DAC
[PXTable(typeof(Location.locationID), typeof(Location.bAccountID), IsOptional = false)]
public class LocationExt : PXCacheExtension<Location>
{
#region Selected
public abstract class selected : IBqlField { }
[PXBool()]
[PXDefault(false)]
[PXUIField(DisplayName = "Selected")]
public virtual bool? Selected { get; set; }
#endregion
#region DateFirstService
public abstract class dateFirstService : IBqlField { }
[PXDBDate()]
[PXUIField(DisplayName = "Date of First Service")]
public virtual DateTime? DateFirstService { get; set; }
#endregion
}
I modelled my solution after several processing screens that I found, but I've looked at so many I couldn't say which ones I used as examples. I've moved the SetProcessDelegate call between the RowSelected event and the Constructor with no luck. I've attempted making the updateLocationStats function static versus not static (using the existing graph instead) with no success.
UPDATE:
Calling the updateLocationStats method directly instead of creating a
copy of the List didn't change the result.
Adding PXFilterable to the PXFilteredProcessingJoin didn't change the result
Removing the calls to locStats (creation, setCommStats(locationLp), Persist) didn't change the result
Added missing Location DAC
Attempted moving Selected from LocationExt DAC to a new LocationAlt : Location DAC with no change in result.
Added DataType="Boolean" to the selected field in the page. No change in behavior
Added BatchUpdate="True" to the PXGrid tag. No change in behavior.
Added PXProcessing.SetProcessed(); after locStats.setCommStats(locationLp); no change in behavior.
Alternate Test
public class LocationAlt : Location
{
#region Selected
public abstract class selected : IBqlField { }
[PXBool()]
[PXDefault(false)]
[PXUIField(DisplayName = "Selected")]
public virtual bool? Selected { get; set; }
#endregion
}
public class CalculateLocationStatsProcess : PXGraph<CalculateLocationStatsProcess>
{
public PXCancel<LocationStatsFilter> Cancel;
public PXFilter<LocationStatsFilter> filterLocStat;
[PXFilterable()]
public PXFilteredProcessingJoin<LocationAlt,
LocationStatsFilter,
InnerJoin<Customer, On<Customer.bAccountID, Equal<LocationAlt.bAccountID>>>,
Where<True, Equal<True>>,
OrderBy<Asc<Customer.acctCD, Asc<LocationAlt.locationCD>>>> processLocations;
public CalculateLocationStatsProcess()
{
}
public virtual void LocationStatsFilter_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
processLocations.SetProcessDelegate(
delegate (List<LocationAlt> list)
{
CalculateLocationStatsProcess.updateLocationStats(list, filterLocStat.Current);
}
);
}
public static void updateLocationStats(List<LocationAlt> locations, LocationStatsFilter filter)
{
var graph = new PXGraph();
var locStats = new CommStatsHelper(graph, filter.TargetDate);
bool erred = false;
for (int iLp = 0; iLp < locations.Count; iLp++)
{
LocationAlt locationLp = locations[iLp];
PXProcessing<LocationAlt>.SetCurrentItem(locationLp);
try
{
locStats.setCommStats(locationLp);
}
catch (Exception ex)
{
erred = true;
PXProcessing<LocationAlt>.SetError(iLp, ex.Message);
}
}
locStats.StatCache.Persist(PXDBOperation.Insert);
locStats.StatCache.Persist(PXDBOperation.Update);
if (erred)
{
throw new PXException("Location(s) failed during recalculation process. View individual lines to see their specific error.");
}
}
}
Note that the alternate test didn't work either.
The problem being experienced is because the originating graph instance (that is the instance of the graph for which you are in when you first enter the screen) isn't maintaining scope to the execution graph instance (that is the instance of the graph which is doing the logic).
For Acumatica to put the processing status logic (e.g. Timer, Green/Red Status circles) it appears the originating graph needs an link to the graph performing the actions. This appears to be handled for you just fine when you point SetProcessDelegate to a method delegate.
In the issue here, you are creating an ad-hoc delegate (by using the delegate keyword in the constructor/rowselected event). The variable declaration (not instantiation) needs to be outside of the delegate.
Corrected Setting of Delegate
CalculateLocationStatsProcess graph = null;
processLocations.SetProcessDelegate((List<Location> list) =>
{
graph = PXGraph.CreateInstance<CalculateLocationStatsProcess>();
CalculateLocationStatsProcess.updateLocationStats(list, filterLocStat.Current);
}
);
Note the first line is before the SetProcessDelegate call. Even though the graph isn't instantiated outside the delegate, the graph pointer is created. Thus it appears when assigned a link is made and the UI updates as desired.
Additional Notes
The selected field still exists as part of the extension
I left the function static but it did work as desired if converted to non static, you simply change CalculateLocationStatsProcess.updateLocationStats(list, filterLocStat.Current); to graph.updateLocationStats(list, filterLocStat.Current);
The delegate declaration can occur in either the Constructor public CalculateLocationStatsProcess() or in the Filter's Row Selected Event Handler public virtual void LocationStatsFilter_RowSelected(PXCache sender, PXRowSelectedEventArgs e) both worked for me.
BatchUpdate="true" isn't necessary.
DataType="Boolean" isn't necessary.
Lastly, the linked Customer__AcctCD clears when the process is finished (the join doesn't appear to keep the fields populated) so some code for displaying the AcctCD on the graph will need changing. Since this wasn't the focus of the question presented, I do not plan to include that code here.
I believe you are missing the Selected data field in your DAC:
#region Selected
public abstract class selected : IBqlField
{
}
protected bool? _Selected = false;
[PXBool]
[PXDefault(false)]
[PXUIField(DisplayName = "Selected")]
public bool? Selected
{
get
{
return _Selected;
}
set
{
_Selected = value;
}
}
#endregion
Instead of using Location directly, create a DAC extension for Location (LocationStat?) where you will add the Selected field. Don't use Location in your processing screen, use the extension containing the selected field.
I have a web form in which i want to show timing label for user,like 180 second,
i have done using following code,
<div>
<asp:ScriptManager ID="SM1" runat="server"></asp:ScriptManager>
<asp:Timer ID="timer1" runat="server" Interval="1000"
OnTick="timer1_tick">
</asp:Timer>
</div>
<div>
<asp:UpdatePanel ID="updPnl" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:Label ID="lblTimer" runat="server"></asp:Label>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="timer1" EventName="tick" />
</Triggers>
</asp:UpdatePanel>
</div>
and code behind
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
Page.Header.Title = "Test";
}
if (!SM1.IsInAsyncPostBack)
Session["TimeCount"] = DateTime.Now.AddSeconds(180).ToString();
}
and
protected void timer1_tick(object sender, EventArgs e)
{
if (0 > DateTime.Compare(DateTime.Now,
DateTime.Parse(Session["TimeCount"].ToString())))
{
lblTimer.Text = "Number of Second Left: " +
((Int32)DateTime.Parse(Session["TimeCount"].
ToString()).Subtract(DateTime.Now).TotalSeconds).ToString();
}
else
{
}
}
problem i am facing that each time user click on button in page counter refresh to 180 again,Secondly this show fix value like 177,170,i want to show that label auto decreasing ?
I'm trying to build main navigation with drop down subnavigation menu anchors. I got the HTML with CSS ready, but I don't know how to do it in the sublayout and its code behind.
I have done a lot of navigations, but those were all 1-dimensional menus using asp:repeaters or asp:ListViews.
Can anyone point me to the right direction?
Essentially you will want to have nested repeaters on the number of levels (or "dimensions") you want to display on your navigation. See an example below.
<asp:Repeater runat="server" ID="TopNavRepeater" OnItemDataBound="TopNavRepeater_OnItemDataBound">
<ItemTemplate>
<sc:Link runat="server" ID="sclTopLink" Field="__Display Name" />
<asp:Repeater runat="server" ID="SecondNavRepeater" OnItemDataBound="SecondNavRepeater_OnItemDataBound">
<ItemTemplate>
<sc:Link runat="server" ID="sclSecondLink" Field="__Display Name" />
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
You will want to get the children of each Item bound to the Top Repeater and bind it to the second Repeater. Use Sitecore Link Controls to render the links to the pages by settings the Items, and Fields, on the OnItemDataBound event.
See below for a rough example
protected void Page_Load(object sender, EventArgs e)
{
TopNavRepeater.DataSource = YourHomeItem.Children();
TopNavRepeater.DataBind();
}
protected void TopNavRepeater_OnItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
var item = e.Item.DataItem as Item;
if (item == null)
return;
var sclTopLink = e.Item.FindControl("sclTopLink") as Link;
var SecondNavRepeater = e.Item.FindControl("SecondNavRepeater") as Repeater;
if (sclTopLink != null)
{
sclTopLink.Item = item;
}
if (SecondNavRepeater != null)
{
SecondNavRepeater.DataSource = item.Children;
SecondNavRepeater.DataBind();
}
}
}
i have one page and 2 user control in it and first user control have dropdownlist and second user control have another dropdown list , when we select dropdownlist of first user control than should be filled another dropdown list of second user control.... how can we achieve it ...please explaing in detain
thanks in advance...
I would expose the child DropDownList's OnSelectedItemChanged event AND the actual DropDownList at the top public level for the user control.
This would allow you to catch the OnSelectedItemChanged event in the Page and set the value of the second user control.
Let me know if you want some sample code.
Ok, so first the user control
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="SampleUserControl.ascx.cs" Inherits="WebApplication1.UserControls.SampleUserControl" %>
<asp:DropDownList runat="server" ID="DdlTest" AutoPostBack="true">
<asp:ListItem Text="Sampe 1" />
<asp:ListItem Text="Sampe 2" />
</asp:DropDownList>
now the file behind that
public partial class SampleUserControl : System.Web.UI.UserControl
{
public DropDownList InternalDropDownList
{
get { return DdlTest; }
}
protected void Page_Load(object sender, EventArgs e)
{
}
}
okay, lets go to the actual .aspx
<form id="form1" runat="server">
<div>
<uc1:SampleUserControl ID="SampleUserControl1" runat="server" />
<uc1:SampleUserControl ID="SampleUserControl2" runat="server" />
</div>
</form>
and the code behind that
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
SampleUserControl1.InternalDropDownList.SelectedIndexChanged += InternalDropDownList_SelectedIndexChanged;
}
void InternalDropDownList_SelectedIndexChanged(object sender, EventArgs e)
{
SampleUserControl2.InternalDropDownList.SelectedValue = SampleUserControl1.InternalDropDownList.SelectedValue;
}
}