Custom DataControlField Class - asp.net

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
}
}

Related

C#, Xamarin Forms: No Custom TextChangedEvent Raised on initialization

I'm creating an Xamarin.Forms MVVM App (only using Android) which needs certain buttons to be outlined red, whenever their text property holds a specific value. (Purpose: alert the user to press the button and select a value, which will change the Button Text Property and therefore remove the red outline)
To achieve this I've create the following documents:
A custom button CButton that extents the default Button:
public class CButton : Button
{
// this Hides the Default .Text-Property
public string Text
{
get => base.Text;
set
{
base.Text = value;
TextChangedEvent(this, new EventArgs());
}
}
// The Raised Event
protected virtual void TextChangedEvent(object sender, EventArgs e)
{
EventHandler<EventArgs> handler = TextChanged;
handler(sender, e);
}
public event EventHandler<EventArgs> TextChanged;
}
A custom behavior makes use of the raised TextChangedEvent
public class ButtonValBehavior : Behavior<CButton>
{
protected override void OnAttachedTo(CButton bindable)
{
bindable.TextChanged += HandleTextChanged;
base.OnAttachedTo(bindable);
}
void HandleTextChanged(object sender, EventArgs e)
{
string forbidden = "hh:mm|dd.mm.yyyy";
if (forbidden.Contains((sender as CButton).Text.ToLower()))
{
//Do when Button Text = "hh:mm" || "dd.mm.yyyy"
(sender as CButton).BorderColor = Color.Gray;
}
else
{
//Do whenever Button.Text is any other value
(sender as CButton).BorderColor = Color.FromHex("#d10f32");
}
}
protected override void OnDetachingFrom(CButton bindable)
{
bindable.TextChanged -= HandleTextChanged;
base.OnDetachingFrom(bindable);
}
}
The relevant parts of the ViewModel look the following:
public class VM_DIVI : VM_Base
{
public VM_DIVI(O_BasisProtokoll base)
{
Base = base;
}
private O_BasisProtokoll _base = null;
public O_BasisProtokoll Base
{
get => _base;
set
{
_base = value;
OnPropertyChanged();
}
}
Command _datePopCommand;
public Command DatePopCommand
{
get
{
return _datePopCommand ?? (_datePopCommand = new Command(param => ExecuteDatePopCommand(param)));
}
}
void ExecuteDatePopCommand(object param)
{
//launch popup
var p = new PP_DatePicker(param);
PopupNavigation.Instance.PushAsync(p);
}
}
The .xmal looks the following (b is the xmlns of the Namespace):
<b:CButton x:Name="BTN_ED_Datum"
Text="{Binding Base.ED_datum, Mode=TwoWay}"
Grid.Column="1"
Command="{Binding DatePopCommand}"
CommandParameter="{x:Reference BTN_ED_Datum}">
<b:CButton.Behaviors>
<b:ButtonValBehavior/>
</b:CButton.Behaviors>
</b:CButton>
This solution works fine whenever the input is caused by user interaction. However, when a Value is assigned during the initialization of the Page no red outline is created, in fact the TextChangedEvent isn't raised. By using breakpoints I noticed that during initialization the Text Property of CButton is never set, eventhough it actually will be in the view.
Despite fiddling around with my solution I cannot make this work on initialization. I tried to work around this issue by outlining every button by default in their constructor, however this will outline every button red, even when their text value doesn't require them to be.
How can I achieve my initial goal?
Many thanks in advance!
It's been a while but if I recall correctly what I ended up doing was:
Changing the new Text-Property of my custom Button to CText and
Making sure that I have Mode=TwoWay activated for any Element, that doesn't have it enabled by default. (Look up Binding modes on msdn for more)
making CText a bindable property of CButton
My custom button now looks the following:
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace EORG_Anton.Model
{
public class CButton : Button
{
public static readonly BindableProperty CTextProperty =
BindableProperty.Create(nameof(CText),
typeof(string),
typeof(CButton),
default(string),
BindingMode.TwoWay,
propertyChanged: OnTextChanged);
private static void OnTextChanged(BindableObject bindable, object oldValue, object newValue)
{
var control = (CButton)bindable;
var value = (string)newValue;
control.CText = value;
}
public string CText
{
get => base.Text;
set
{
base.Text = value;
TextChangedEvent(this, new EventArgs());
}
}
protected virtual void TextChangedEvent(object sender, EventArgs e)
{
EventHandler<EventArgs> handler = TextChanged;
handler(sender, e);
}
public event EventHandler<EventArgs> TextChanged;
}
}

Is it possible to change the border of a single Entry in xamarin forms?

I was wondering if someone can point out how I can change a single entry?. I've made a custom renderer which changes the border of an entry to red but what I really want is only to change one entry if validation fails from black to red.
Picture of entries:
My renderer:
[assembly: ExportRenderer(typeof(App.RedFrameEntry), typeof(RedFrameEntryRenderer))]
namespace App.iOS
{
public class RedFrameEntryRenderer : EntryRenderer
{
public bool isInvalid = false;
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.BorderStyle = UITextBorderStyle.RoundedRect;
Control.Layer.CornerRadius = 4;
Control.Layer.BorderColor = Color.FromHex("#c60303").ToCGColor();
Control.Layer.BorderWidth = 0;
if (isInvalid)
{
Control.Layer.BorderWidth = 2;
}
}
}
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
}
}
}
And my code:
private void ChangeEntryOnValidationFail(string text, Entry entry, int numberOfChar)
{
if (String.IsNullOrEmpty(text) || text.Length < numberOfChar)
{
// TODO: Change to RedFrameEntry
}
else
{
// TODO: Change back to default
}
}
I'd suggest you create a CustomEntry class which has a base class of Entry, so instead of changing the border of all entries, you can just call the CustomEntry whenever you need it.
public class CustomEntry : Entry{
}
then use:
[assembly: ExportRenderer(typeof(CustomEntry), typeof(RedFrameEntryRenderer))]
Hope it helps!

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>

Adding Action listener for buttons created by method

Ok if i have the following code:
protected void makebutton(String name){
JButton button = new JButton(name);
mypanel.add(button);
}
then:
makebutton("Button1");
makebutton("Button2");
makebutton("Button3");
How can i add ActionListener to them. Which name do I use for ActionListener, tried many combination but no success.
What you could do is make the method return a Button. Thats way you can use the button variable else where in your program. What's happening in your case is that the button is encapsulated. so you can't access from anywhere else in your code. Something like this
private JButton makeButton(String name){
JButton button = new JButton(name);
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
// code action to perform
}
});
return button;
}
You can use the method when you declare the button
JButton aButton = makeButton();
panel.add(aButton);
The more reasonable way to do it is just create the buttons without a method.
JButtton button = new JButton("Button");
panel.add(button);
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
// code action to perform
}
});
I don't really see the need for a method.
Another option is to create a custom listener class
public class GUI {
JButton button1;
JButton button2;
public GUI(){
button1 = new JButton();
button2 = new JButton();
button1.addActionListner(new ButtonListener());
button2.addActionListner(new ButtonListener());
}
private class ButtonListener implements ActionListener{
public void actionPerformed(ActionEvent e){
if (e.getSource() == button1){
// do something
} else if (e.getSource() == button2){
// something
}
}
}
}
protected void makebutton(String name){
final String n = name;
JButton button = new JButton(name);
mypanel.add(button);
button.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
if(n=="Button1"){
button1ActionListener();
}else if(n=="Button2"){
button2ActionListener();
}
}
});
}
you have to create more methods for every button.
I think peeskillet's second code is the good one.

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

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;
}
}
}
}
}

Resources