count of controls used in each page of an ASP.Net application? - asp.net

Is there any way to find out the count of controls used in each page of an ASP.Net application?
Please help

Why do you need it? Define controls first, everything that derives from System.Web.UI.Control?
You could write a recursive extension method which which returns all controls lazily, then it is simple:
protected void Page_PreRender(object sender, EventArgs e)
{
var allControls = this.GetControlsRecursively().ToList();
}
Here a possible implementation:
public static class ControlExtensions
{
public static IEnumerable<Control> GetControlsRecursively(this Control parent)
{
foreach (Control c in parent.Controls)
{
yield return c;
if (c.HasControls())
{
foreach (Control control in c.GetControlsRecursively())
{
yield return control;
}
}
}
}
}

Related

Xamarin Forms - UWP custom renderer: how to add a child to a stacklayout

I'm trying to insert a UWP specific child in the custom renderer of a StackLayout.
However, in the sample code below, Control is always null whereas my StackLayout has Children. Maybe StackPanel is not what StackLayout is rendered into in UWP.
public class MyRenderer : ViewRenderer<StackLayout, StackPanel>
{
private bool _childAdded;
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (!_childAdded && Control?.Children != null)
{
_childAdded = true;
Control.Children.Insert(0, new Windows.UI.Xaml.Shapes.Rectangle());
}
base.OnElementPropertyChanged(sender, e);
}
}
Some modification in you are cade because you are calling base.OnElementPropertyChanged(sender,e) after code implementation. Just try to use below code.
public class MyRenderer : ViewRenderer<StackLayout, StackPanel>
{
private bool _childAdded;
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if(Control==null)
return;
if (!_childAdded && Control.Children != null)
{
_childAdded = true;
Control.Children.Insert(0, new Windows.UI.Xaml.Shapes.Rectangle());
}
}
}
The StackLayout (Layout) renderer is ViewRenderer and implemented on UWP by FrameworkElement; Renderer Base Classes and Native Controls.
Theoretical renderer:
public class MyRenderer : ViewRenderer<StackLayout, FrameworkElement>
...
Control is always null whereas my StackLayout has Children. Maybe StackPanel.
Derive from official document,
In Xamarin.Forms, all layout classes derive from the Layout<T> class and constrain the generic type to View and its derived types. But the layout of children element is incorrect.
And the match Native control within UWP platform is LayoutRenderer. So it is not inherit StackPanel directly. You could also custom a customrederer like the follow.
[assembly: ExportRenderer(typeof(StackLayout), typeof(ICustomStackLayoutRenderer))]
namespace CustomStackLayoutRenderer.UWP
{
public class ICustomStackLayoutRenderer : ViewRenderer<StackLayout, StackPanel>
{
private bool _childAdded;
protected override void OnElementChanged(ElementChangedEventArgs<StackLayout> e)
{
base.OnElementChanged(e);
if (Control == null)
{
var stacklayout = new StackPanel();
SetNativeControl(stacklayout);
}
if (e.OldElement != null)
{
}
if (e.NewElement != null)
{
if (!_childAdded && Control.Children != null)
{
_childAdded = true;
Control.Children.Insert(0, new Windows.UI.Xaml.Shapes.Rectangle() { Width = 100, Height = 100, Fill = new SolidColorBrush(Colors.Red) });
}
}
}
}
}
For your requirement, the better way is that create a CustomStackLayout inherit StackLayout in Xamarin.Forms, and re-layout your children element in your LayoutChildren override method. For more detail you could refer Creating a Custom Layout.

Rearranging parent-child activation order in Caliburn Micro

During my override of OnActivate() in my view-model, I need to call GetView() in order to focus an element. When I do this after I have previously activated my view, it's fine. But when I call this the first activation, it fails.
I was able to get it to work by swapping a few lines in ConductorBaseWithActiveItem.ChangeActiveItem. The original is as follows:
protected virtual void ChangeActiveItem(T newItem, bool closePrevious) {
ScreenExtensions.TryDeactivate(activeItem, closePrevious);
newItem = EnsureItem(newItem);
if(IsActive)
ScreenExtensions.TryActivate(newItem);
activeItem = newItem;
NotifyOfPropertyChange("ActiveItem");
OnActivationProcessed(activeItem, true);
}
and with my changes:
protected virtual void ChangeActiveItem(T newItem, bool closePrevious) {
ScreenExtensions.TryDeactivate(activeItem, closePrevious);
newItem = EnsureItem(newItem);
activeItem = newItem;
NotifyOfPropertyChange("ActiveItem");
if (IsActive)
ScreenExtensions.TryActivate(newItem);
OnActivationProcessed(activeItem, true);
}
This seems to work. Notifying that "ActiveItem" changed triggers the code to load and cache the view. Then ScreenExtensions.TryActivate calls my OnActivate override.
Question: I haven't noticed any problems doing this, but I'm curious if anyone knows better than I do what repercussions this change could have?
Thanks!
One thing you could try is overriding Caliburn's OnViewAttached method and trying to focus it there. That being said, in MVVM, focus is more of a View concern, so if possible, that logic should be moved from the ViewModel to the View.
One way you may be able to solve this is by creating an attached behavior (you will need a reference to the Microsoft.Expression.Interactions assembly):
public class FocusWhenVisibleBehavior : Behavior<FrameworkElement>
{
protected override void OnAttached()
{
this.AssociatedObject.Loaded += this.Loaded;
this.AssociatedObject.IsVisibleChanged += this.VisibleChanged;
}
protected override void OnDetaching()
{
this.AssociatedObject.Loaded -= this.Loaded;
this.AssociatedObject.IsVisibleChanged -= this.VisibleChanged;
}
private void Loaded(object sender, RoutedEventArgs e)
{
this.TryFocus();
}
private void VisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
this.TryFocus();
}
private void TryFocus()
{
if (this.AssociatedObject.IsLoaded && this.AssociatedObject.IsVisible)
{
// Focus the control
this.AssociatedObject.Focus();
}
}
}
And that attaching that behavior to whatever control you want to focus:
<Button>
<i:Interaction.Behaviors>
<b:FocusWhenVisibleBehavior/>
</i:Interaction.Behaviors>
</Button>

ASP.NET Back Button for multiple forms

I am trying to track navigation between a number of Web Forms in ASP.NET. I've tried the client side back navigation using the following:
<asp:Button ID="BackButton" runat="server" Text="Back"
OnClientClick="JavaScript:window.history.back(1);return false;" />
Unfortunately this does not work for my scenario due to postbacks going on. My scenario has a number of Web Forms:
Page1.1
Page1.2
Page2
Page3
Navigating forward through the pages works similarly to a wizard. There are 2 starting points - from Page1.1 and Page1.2.
Page1.1 -> Page2 -> Page3
Page1.2 -> Page2 -> Page3
So clicking back buttons will have the following navigation:
Page3 -> Page2
Page2 -> Page1.1
Page2 -> Page1.2
There are additional parameters passed between the pages which need to be maintained.
I am currently looking at maintaining something in the Session to maintain the current call stack which somewhat works however, I am getting a build up of referrer urls. At the minute I am just trying to conceptualise this.
I am running this in SharePoint as Application Pages, however each page is essentially an ASP.NET page for the sake of this example.
So I have introduced an abstract class for each Page:
public abstract class SecureLayoutsPageBase : System.Web.UI.Page
{
private PageController _pageController;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
_pageController = (PageController)Session["PageController"];
if (_pageController == null)
{
_pageController = new PageController();
Session["PageController"] = _pageController;
}
if (!Page.IsPostBack && Page.Request.UrlReferrer != null)
{
this.PageController.History.Push(Page.Request.UrlReferrer.ToString());
}
}
protected PageController PageController
{
get
{
return _pageController;
}
}
}
Which has an instance of PageController:
[Serializable()]
public class PageController
{
private Stack<string> _history = new Stack<string>();
public void Previous(HttpResponse response)
{
string previous = _history.Pop();
response.Redirect(previous);
}
public Stack<string> History
{
get
{
return _history;
}
}
}
Then each page will call the PageController.Previous in the server side event handler for the back button click:
protected void BackButton_Click(object sender, EventArgs e)
{
this.PageController.Previous(this.Response);
}
This issue with this is that calling PageController.Previous still results in the Url being added to the stack. I am just wondering if there is a way to prevent the url getting added when back has been clicked. Or alternative solutions...
History(-1) wont work, because this will include postbacks. Just set the button href dependant on whatever page you're on. If you know itsloaded page 3, set the back button to page 2
OK... couple of tweaks to get my scenario working. Not keen on this solution so any others would be good.
Change to SecureLayoutsPageBase:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
_pageController = (PageController)Session["PageController"];
if (_pageController == null)
{
_pageController = new PageController();
Session["PageController"] = _pageController;
}
if (!Page.IsPostBack && Page.Request.UrlReferrer != null && Page.Request.Url.ToString() != this.PageController.PreviousUrl)
{
this.PageController.AddHistory(Page.Request.UrlReferrer.ToString());
}
}
Change to PageController:
[Serializable()]
public class PageController
{
private Stack<string> _history = new Stack<string>();
private string _previous;
public void Previous(HttpResponse response)
{
_previous = _history.Pop();
response.Redirect(_previous);
}
public void AddHistory(string url)
{
if(url != _previous)
{
_history.Push(url);
}
}
public Stack<string> History
{
get
{
return _history;
}
}
public string PreviousUrl
{
get
{
return _previous;
}
}
}

Silverlight Listbox: Binding does not get updated

I have a Wizard control that has multiple steps. Controls that are not visible get removed from the visual tree. I have a ListBox on one page, that binds to an ObservableCollection<T>. When items get added or removed to that ListBoxon one page, the ListBox on another page (with the same ItemsSource), the binding on the other page does not get updated. I hope this explains my problem clearly enough.
How do I get this binding to update when the page gets added to the visual tree again ?
I cannot reproduce your problem. I was able to remove a ListBox from the visual tree, add objects to the ObservableCollection, and when I add it to the visual tree, items are actually updated.
Try working around your problem by setting visibility to Collapsed rather than removing from Visual Tree.
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.listBox1.ItemsSource = o;
this.listBox2.ItemsSource = o;
}
ObservableCollection<int> o = new ObservableCollection<int>();
private void buttonList1_Click(object sender, RoutedEventArgs e)
{
if (this.listBox1.Parent == null)
this.LayoutRoot.Children.Add(this.listBox1);
else
this.LayoutRoot.Children.Remove(this.listBox1);
//this.listBox1.Visibility = this.listBox1.Visibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
}
private void buttonList2_Click(object sender, RoutedEventArgs e)
{
if (this.listBox2.Parent == null)
this.LayoutRoot.Children.Add(this.listBox2);
else
this.LayoutRoot.Children.Remove(this.listBox2);
//this.listBox2.Visibility = this.listBox2.Visibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
}
private void ButtonAddMore_Click(object sender, RoutedEventArgs e)
{
o.Add(o.Count);
}
}

Custom DataControlField Class

I did some search but nothing is really useful in my case.
I want to inherit the DataControlField (System.Web.UI.WebControls) to be able to carry two label controls and then I want to color the two labels to get some sort of conditional formatting, I've got the conditional formatting part but how can I customize this class?
Where in my class should I define the two label controls?
How would I override the CreateField method?
P.S: I know I can accomplish this, in XHTML Markup, but I have so many columns that it would not be appropriate to include those markups in the page markup. Therefore I'm doing that in the CodeBehind page.
EDIT:
public class MyField : DataControlField
{
public MyField()
{
}
protected override DataControlField CreateField()
{
// What to put here?
}
protected override void CopyProperties(DataControlField newField)
{
((CalendarField)newField).DataField = this.DataField;
((CalendarField)newField).DataFormatString = this.DataFormatString;
((CalendarField)newField).ReadOnly = this.ReadOnly;
base.CopyProperties(newField);
}
public override void InitializeCell(DataControlFieldCell cell, DataControlCellType cellType, DataControlRowState rowState, int rowIndex)
{
// Call the base method
base.InitializeCell(cell, cellType, rowState, rowIndex);
// Initialize the contents of the cell quitting if it is a header/footer
if (cellType == DataControlCellType.DataCell)
InitializeDataCell(cell, rowState);
}
protected virtual void InitializeDataCell(DataControlFieldCell cell, DataControlRowState rowState)
{
}
}
See here. Hope this helps you.
public class MyField : DataControlField {
public MyField() { }
protected override DataControlField CreateField() {
// What to put here?
return new MyField();
}
protected override void CopyProperties(DataControlField newField) {
((CalendarField)newField).DataField = this.DataField;
((CalendarField)newField).DataFormatString = this.DataFormatString;
((CalendarField)newField).ReadOnly = this.ReadOnly;
base.CopyProperties(newField);
}
public override void InitializeCell(DataControlFieldCell cell, DataControlCellType cellType, DataControlRowState rowState, int rowIndex)
{
// Call the base method
base.InitializeCell(cell, cellType, rowState, rowIndex);
// Initialize the contents of the cell quitting if it is a header/footer
if (cellType == DataControlCellType.DataCell)
{
cell.DataBinding += new EventHandler(cell_DataBinding);
}
}
void cell_DataBinding(object sender, EventArgs e)
{
Control ctrl = sender as Control;
var container = ctrl.NamingContainer as IDataItemContainer;
// here what you would like to show in MyField
}
}

Resources