Adding a Click Event to a Button in a Different Class - c#

I am trying to add a click event to a button that is defined in a different class.
Just a quick overview, this code creates a stack of cards with buttons on them and the buttons need click events.
The CardView class:
public class CardView : ContentView
{
public Label Name { get; set; }
public Image Photo { get; set; }
public Label Location { get; set; }
public Label Description { get; set; }
public Button PassButton { get; set; }
public Button FailButton { get; set; }
public CardView()
{
// gives the card its black line
Grid grid = new Grid();
grid.BackgroundColor = Color.Black;
grid.Padding = 2;
RelativeLayout view = new RelativeLayout();
// box view as the background
BoxView boxView1 = new BoxView
{
Color = Color.White,
InputTransparent = true
};
view.Children.Add(boxView1,
Constraint.Constant(0), Constraint.Constant(0),
Constraint.RelativeToParent((parent) => {
return parent.Width;
}),
Constraint.RelativeToParent((parent) => {
return parent.Height;
})
);
// items image
Photo = new Image()
{
InputTransparent = true,
Aspect = Aspect.Fill
};
view.Children.Add(Photo,
Constraint.Constant(0),
Constraint.RelativeToParent((parent) =>
{
double h = parent.Height * 0.80;
return ((parent.Height - h) / 2) + 20;
}),
Constraint.RelativeToParent((parent) =>
{
return parent.Width;
}),
Constraint.RelativeToParent((parent) =>
{
return (parent.Height * 0.40);
})
);
// items label
Name = new Label()
{
TextColor = Color.Black,
FontSize = 22,
InputTransparent = true,
FontAttributes = FontAttributes.Bold,
HorizontalOptions = LayoutOptions.CenterAndExpand,
HorizontalTextAlignment = TextAlignment.Center
};
view.Children.Add(Name,
Constraint.Constant(10), Constraint.Constant(10),
Constraint.RelativeToParent((parent) =>
{
return parent.Width;
}),
Constraint.Constant(28)
);
// location description
Location = new Label()
{
TextColor = Color.Black,
FontSize = 18,
InputTransparent = true
};
view.Children.Add(Location,
Constraint.Constant(30), Constraint.Constant(40),
Constraint.RelativeToParent((parent) =>
{
return parent.Width;
}),
Constraint.Constant(28)
);
//Image[] stars = new Image[5];
StackLayout stack = new StackLayout
{
Orientation = StackOrientation.Horizontal,
Spacing = 2
};
view.Children.Add(stack,
Constraint.RelativeToParent((parent) =>
{
return parent.Width - 90; //
}),
Constraint.Constant(40)); //40
// bottom label
Description = new Label()
{
TextColor = Color.Black,
FontSize = 16,
FontAttributes = FontAttributes.None,
HorizontalOptions = LayoutOptions.CenterAndExpand,
HorizontalTextAlignment = TextAlignment.Center,
InputTransparent = true
};
view.Children.Add(
Description,
Constraint.Constant(0),
Constraint.RelativeToParent((parent) =>
{
return (parent.Height / 2f) + 30;
}),
Constraint.RelativeToParent((parent) =>
{
return parent.Width;
}),
Constraint.Constant(40)
);
// camera button
Button camera = new Button()
{
Text = "Camera",
InputTransparent = true
};
view.Children.Add(camera,
Constraint.RelativeToParent((parent) =>
{
return (parent.Width / 2f) - (camera.Width / 2f);
}),
Constraint.RelativeToParent((parent) =>
{
return parent.Height - 70;
})
);
PassButton = new Button()
{
Text = "Pass",
};
view.Children.Add(PassButton,Constraint.RelativeToParent((parent)=>
{
return (parent.Width / 8f) - (PassButton.Width / 4f);
}),
Constraint.RelativeToParent((parent) =>
{
return parent.Height - 70;
})
);
FailButton = new Button()
{
Text = "Fail",
};
view.Children.Add(FailButton, Constraint.RelativeToParent((parent) =>
{
return (parent.Width *(3/ 4f)) - (FailButton.Width / 4f);
}),
Constraint.RelativeToParent((parent) =>
{
return parent.Height - 70;
})
);
grid.Children.Add(view);
Content = grid;
}
}
This class is used as sort of a template for the entire deck.
In another class multiple instances of the CardView class are created to make the deck of cards.
The creation of the cards is working fine.
So in the CardStackView (in the constructor) the deck is created:
public CardStackView()
{
RelativeLayout view = new RelativeLayout();
// create a stack of cards
for (int i = 0; i < NumCards; i++) //
{
var card = new CardView();
cards[i] = card;
card.InputTransparent = true;
card.IsVisible = false;
view.Children.Add(
card,
Constraint.Constant(0),
Constraint.Constant(0),
Constraint.RelativeToParent((parent) =>
{
return parent.Width;
}),
Constraint.RelativeToParent((parent) =>
{
return parent.Height;
})
);
}
this.BackgroundColor = Color.Azure;
this.Content = view;
}
Is it possible to add click events/tapgestures to the buttons in the CardView class (PassButton and FailButton) in the constructor of the CardStackView when the deck is being created?
They kind of need to be added here given the nature of the rest of the CardStackView. There is a lot going on and its not feasible to reorganise the code at this point.
Is it even possible to do this?
Also things I have tried.
I tried using the instance of the CardView in the for loop to access the button and add the events but this simply did nothing.
i.e card.PassButton.Clicked += clickEvent.
Any ideas? Or even if it is possible?

Here we go.
I think that buttons, labels and image inside the CardView can be private variables, so you can deal with it in a more controlled way (the outside class should not change the position of the button inside your card, for example)
There's a lot of ways to do that. I thought 2 ways given your code structure:
- 1 Encapsulating the event handler definition
You can create a method in your CardView like:
public class CardView : ContentView
{
// Your stuffs
public void AddPassButtonClickedEvent(EventHandler handler)
{
if(handler != null)
PassButton.Clicked += handler;
}
// Your stuffs
}
Outside the class, you will use it like:
var cardView = new CardView();
cardView.AddPassButtonClickedEvent((sender, args) =>
{
// Do something
});
- 2 Exposing your own event
You can create your own events (or commands) at the CardView class and always asign the clicked event of the button. Like this:
public class CardView : ContentView
{
// Your stuffs
public event EventHandler MyPassButtonClickedEvent;
public CardView()
{
// Instantiate your PassButton
PassButton.Clicked += OnPassButtonClicked;
}
protected void OnPassButtonClicked(object sender, EventArgs args)
{
MyPassButtonClickedEvent?.Invoke(object, args);
}
// Your stuffs
}
Again, you can use it outside this way:
class Fake
{
CardView cardView;
public Fake()
{
cardView = new CardView();
cardView.MyPassButtonClickedEvent += MyHandler;
}
void MyHandler(object sender, EventArgus args)
{
// Do something
}
}

Related

Get multiple returns from one string function

Based on /users/668272/bas dialog box. I tried writing more in order to get multiple values
public static class ControlInfo
{
public static TextBox[] TextData { get; set; }
}
public static class Prompt
{
public static Form prompt = new Form();
public static void ShowDialog(string Text, string caption)
{
//string[] inputval = new string[6];
prompt = new Form()
{
Width = 500,
Height = 650,
FormBorderStyle = FormBorderStyle.FixedDialog,
Text = caption,
StartPosition = FormStartPosition.CenterScreen
};
#region:create
Label textLabel = new Label() { Left = 20, Top = 20, Text = Text };
TextBox textBox1 = new TextBox() { Left = 50, Top = 100, Width = 400 };
Button confirmationok = new Button()
{ Text = "Save", Left = 250, Width = 100, Top = 550, DialogResult = DialogResult.OK };
Button confirmationcancel = new Button()
{ Text = "Cancel", Left = 350, Width = 100, Top = 550, DialogResult = DialogResult.Cancel };
confirmationok.Click += (sender, e) => { Save(); };
confirmationcancel.Click += (sender, e) => { prompt.Close(); };
prompt.Controls.Add(confirmationcancel);
prompt.Controls.Add(textBox1);
prompt.Controls.Add(textBox2);
prompt.Controls.Add(textBox3);
prompt.Controls.Add(textBox4);
prompt.Controls.Add(textBox5);
prompt.Controls.Add(textBox6);
prompt.Controls.Add(confirmationok);
prompt.Controls.Add(textLabel);
prompt.Controls.Add(textLabel1);
prompt.Controls.Add(textLabel2);
prompt.Controls.Add(textLabel3);
prompt.Controls.Add(textLabel4);
prompt.Controls.Add(textLabel5);
prompt.Controls.Add(textLabel6);
prompt.AcceptButton = confirmationok;
prompt.AcceptButton = confirmationcancel;
prompt.ShowDialog();
}
public static void Save()
{
var cArray = prompt.Controls.OfType<TextBox>().ToArray();
ControlInfo.TextData = cArray;
}
}
[Update] I tried using string[] to get the values but this keeps on happening: return inputval; 'Index was outside the bounds of the array.' So how do I return the values to string[] array properly?
[Update 2] Fixed the problem by creating a TextData[] to store the values then calling it out like this ControlInfo.TextData[0].Text
I used a Textdata class to store the values from dialog through SAVE button. The completed code is in the question

Create multiple textbox dynamically in single form using c#?

My aim is to create a .dll file dynamically having TextBox,Button which can be used by anyone in a program using Visual C#.
It would get created in Class Library, No WFA tools would get used.
I need help in creating a form which can generate multiple TextBox according to the attributes provided by the user.
1)No of TextBox
2)Location
3)Size etc
Code
CLASS.CS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
namespace Forms
{
public class TextForm : Form
{
public TextBox txtBox1;
public TextForm(int a, int b, int c, int d, string e)
{
Form f1 = new Form();
txtBox1 = new TextBox();
txtBox1.Visible = true;
//f1.ActiveControl=txtBox1;
f1.Controls.Add(txtBox1);
txtBox1.Focus();
f1.Visible = true;
txtBox1.Size = new Size(a, b);
txtBox1.Location = new Point(c, d);
txtBox1.Text = (e).ToString();
this.Controls.Add(txtBox1);
txtBox1.Visible = true;
}
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
}
}}
PROGRAM.CS
using System;
using Forms;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
TextForm Box1 = (new TextForm(150, 14, 20, 32, "This is a TextBox 1"));
TextForm Box2 = (new TextForm(180, 34, 40, 52, "This is a TextBox 2"));
}}}
What should be the code?
The problem is that you are creating a Form for each TextBox. This is not what you want, provided that you plan to have forms with multiple text boxes.
I see two possibilities: you either want to create a) a textbox that you can easily add to your form, or b) a form with textboxes.
public class TextInput : Form
{
public TextBox TxtBox {
get; private set;
}
public Control Container {
get; private set;
}
public TextInput(Control c, int a, int b, int c, int d, string e)
{
this.Container = c;
this.TxtBox = new TextBox();
var txtBox1 = this.TxtBox;
txtBox1.Visible = true;
c.Controls.Add(txtBox1);
txtBox1.Focus();
txtBox1.Size = new Size(a, b);
txtBox1.Location = new Point(c, d);
txtBox1.Text = (e).ToString();
txtBox1.Visible = true;
}
}
You'd use this as follows:
var f = new Form();
var txtBox1 = new TextInput( f, 100, 25, 10, 10, "Name" );
var txtBox1 = new TextInput( f, 100, 25, 10, 50, "Age" );
var txtBox1 = new TextInput( f, 100, 25, 10, 100, "Address" );
var txtBox1 = new TextInput( f, 100, 25, 10, 150, "Phone" );
The second possibility is much more interesting, in my opinion. You want to create a special Form that automatically adds text boxes as soon a you call a simple method. I'm going to simplify your code, though. It is not a good idea (at all), to use absolute positioning in your forms.
The following creates a form with text boxes and their labels. The textboxes occupy the whole width of the form. This is achieved by using a TableLayoutPanel in which a Panel subPanel is used for each row.
This subPanel holds a label and a text box.
public class InputForm: Form {
public InputForm()
{
this.Panel = new TableLayoutPanel{ Dock = DockStyle.Fill };
this.textBoxes = new List<TextBox>();
this.Controls.Add( this.Panel );
}
public TextBox AddTextBox(string label)
{
var subPanel = new Panel { Dock = DockStyle.Top };
var lblLabel = new Label { Text = label, Dock = DockStyle.Left };
var tbEdit = new TextBox{ Dock = DockStyle.Fill };
subPanel.Controls.Add( tbEdit );
subPanel.Controls.Add( lblLabel );
this.Panel.Controls.Add( subPanel );
return tbEdit;
}
public TableLayoutPanel Panel {
get; private set;
}
public TextBox[] TextBoxes {
get {
return this.textBoxes.ToArray();
}
}
private List<TextBox> textBoxes;
}
You can use this with the following simple code:
var form = new InputForm();
var tbName = form.AddTextBox( "Name" );
var tbAge = form.AddTextBox( "Age" );
var tbAddress = form.AddTextBox( "Address" );
form.Show();
Application.Run( form );
If you'd like to give a few attributes to the text boxes to be created (colors, font, bold...), then you have two ways. The first one is to add parameters to the AddTextBox() method, though that would not scalate well as long as the number of attributes grows. The alternative is to create a TextBoxAttributes class, which will hold the configuring attributes for a given TextBox.
public class InputForm: Form {
public class TextBoxAttributes {
public TextBoxAttributes() {
this.ForeColor = DefaultForeColor;
this.BackColor = DefaultBackColor;
this.Font = DefaultFont;
}
public Color ForeColor {
get; set;
}
public Color BackColor {
get; set;
}
public Font Font {
get; set;
}
public bool Bold {
get {
return this.Font.Bold;
}
set {
var style = FontStyle.Regular;
if ( value ) {
style = FontStyle.Bold;
}
this.Font = new Font( this.Font, style );
}
}
public bool Italic {
get {
return this.Font.Bold;
}
set {
var style = FontStyle.Regular;
if ( value ) {
style = FontStyle.Italic;
}
this.Font = new Font( this.Font, style );
}
}
public bool Underline {
get {
return this.Font.Bold;
}
set {
var style = FontStyle.Regular;
if ( value ) {
style = FontStyle.Underline;
}
this.Font = new Font( this.Font, style );
}
}
public float FontSize {
get {
return this.Font.Size;
}
set {
this.Font = new Font( this.Font.FontFamily, value );
}
}
}
// ... more things...
public TextBox AddTextBox(string label)
=> this.AddTextBox( label, new TextBoxAttributes() );
public TextBox AddTextBox(string label, TextBoxAttributes attr)
{
var subPanel = new Panel { Dock = DockStyle.Top };
var lblLabel = new Label { Text = label, Dock = DockStyle.Left };
var tbEdit = new TextBox{
Dock = DockStyle.Fill,
ForeColor = attr.ForeColor,
BackColor = attr.BackColor,
Font = attr.Font
};
subPanel.Controls.Add( tbEdit );
subPanel.Controls.Add( lblLabel );
this.Panel.Controls.Add( subPanel );
return tbEdit;
}
// ... more things...
}
The main code would be:
public static void Main()
{
var form = new InputForm();
var tbName = form.AddTextBox( "Name", new InputForm.TextBoxAttributes {
ForeColor = Color.Yellow,
BackColor = Color.Blue
});
var tbAge = form.AddTextBox( "Age", new InputForm.TextBoxAttributes {
ForeColor = Color.Green,
BackColor = Color.Black,
Bold = true
});
var tbAddress = form.AddTextBox( "Address" );
form.Show();
Application.Run( form );
}
Hope this helps.
If you are willing to switch to WPF this will become a lot easier, since you can profit from Autolayout and Bindings.
You could easily switch the Wrappanel for a StackPanel or a DockPanel.
The class will create a View based on the public properties of the handed over object. You might have to add additional Types to the Types-Dictionary. In my case those two where sufficient.
Create a Property of the DynamicControl and Bind to it in XAML.
XAML:
<ContentPresenter Content="{Binding Path=DynView}" />
public ViewModel
{
public UserControl DynView {get; private set};
private ModelType _model;
public ViewModel(ModelType model)
{
_model = model;
DynView = new DynamicControl<ModelType>(_model);
}
}
public class DynamicControl<T> : UserControl
{
static DynamicControl()
{
Types[typeof(bool)] = (binding) =>
{
CheckBox cb = new CheckBox();
cb.SetBinding(CheckBox.IsCheckedProperty,binding);
return cb;
};
Types[typeof(String)] = (binding) =>
{
TextBox tb = new TextBox();
tb.SetBinding(TextBox.TextProperty, binding);
return tb;
};
// add additional Types if necessary
}
private T _model;
public DynamicControl(T model)
{
_model = model;
WrapPanel wp = new WrapPanel();
foreach (PropertyInfo pi in model.GetType().GetProperties())
{
Grid g = new Grid();
g.Margin = new Thickness(5, 5, 25, 5);
g.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
g.ColumnDefinitions.Add(new ColumnDefinition());
g.ColumnDefinitions.Add(new ColumnDefinition());
g.RowDefinitions.Add(new RowDefinition());
TextBlock tb = new TextBlock() { Text = pi.Name };
tb.VerticalAlignment = VerticalAlignment.Center;
Grid.SetColumn(tb, 0);
Grid.SetRow(tb, 0);
g.Children.Add(tb);
System.Windows.FrameworkElement uie = GetUiElement(pi);
uie.Margin = new Thickness(10, 0, 0, 0);
uie.VerticalAlignment = VerticalAlignment.Center;
Grid.SetColumn(uie, 1);
Grid.SetRow(uie, 0);
g.Children.Add(uie);
wp.Children.Add(g);
}
this.Content = wp;
}
private FrameworkElement GetUiElement(PropertyInfo pi)
{
System.Windows.Data.Binding binding = new System.Windows.Data.Binding(pi.Name);
binding.Source = _model;
Func<System.Windows.Data.Binding, FrameworkElement> func;
FrameworkElement uie = null;
if (Types.TryGetValue(pi.PropertyType, out func))
uie = func(binding);
else
uie = Types[typeof(String)](binding);
return uie;
}
private static Dictionary<Type, Func<System.Windows.Data.Binding, FrameworkElement>> Types = new Dictionary<Type, Func<System.Windows.Data.Binding, FrameworkElement>>();
}
I think you're going at this all wrong. Just define your dimensions and text in advance, put them in a data class, and then feed a list of those data classes to your form constructor so it can construct them all on the fly.
The data class:
public class TextboxInfo
{
public Int32 Width { get; set; }
public Int32 Height { get; set; }
public Int32 X { get; set; }
public Int32 Y { get; set; }
public String Text { get; set; }
public TextboxInfo(Int32 w, Int32 h, Int32 x, Int32 y, String text)
{
this.Width = w;
this.Height = h
this.X = x;
this.Y = y
this.Text = text;
}
}
The code to construct the form:
public class TextForm : Form
{
public TextBox[] TextBoxes
{
get { return _textBoxes.ToArray(); }
}
private List<TextBox> _textBoxes;
public TextForm(TextboxInfo[] textboxes, Int32 padX, Int32 padY)
{
_textBoxes = new List<TextBox>();
Int32 reqWidth = 0;
Int32 reqHeight = 0;
foreach (TextboxInfo tbi in textboxes)
{
reqWidth = Math.Max(reqWidth, tbi.X + tbi.Width);
reqHeight = Math.Max(reqHeight, tbi.Y + tbi.Height);
TextBox txtB = new TextBox();
txtB.Size = new Size(tbi.Width, tbi.Height);
txtB.Location = new Point(tbi.X, tbi.Y);
txtB.Text = tbi.Text;
_textBoxes.Add(txtB);
this.Controls.Add(txtB);
}
// You may want to add some kind of OK button at the end here (based on reqHeight)
// and link that to a click listener that closes the form.
// Don't forget to adjust your reqHeight to the added height of that button!
// ...
// Set form to the minimum needed size according to its elements.
this.Size = new Size(reqWidth + padX, reqHeight + padY);
}
}
The calling code:
class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
TextboxInfo[] info = new TextboxInfo[2];
info[0] = new TextboxInfo(150, 14, 20, 32, "This is a TextBox 1");
info[1] = new TextboxInfo(180, 34, 40, 52, "This is a TextBox 2");
TextForm frm = new TextForm(info, 20, 32);
frm.ShowDialog();
// Now you can access the form's text box values through frm.TextBoxes[i].Text
}
}
Mind you, this whole system may seem useful at first, but consider that none of the text boxes have labels on them. Just starting values.
I've made systems for custom data before in a project I created, to generate a custom save options dialog depending on the chosen file type to save to, since each file type needed specific options.
Realistically, you'd create a form with some kind of description at the top and an OK and a Cancel button at the bottom, with a panel in between which has its vertical scrollbar set to enable-when-needed. Then you can dynamically put different custom controls in there to support different data types, like say, a checkbox, a text field, a numeric field, et cetera. They'll automatically be listed vertically in the list simply by keeping track of each control's height to get the next control's Y-offset, and if they'd exceed the form size the panel will make sure you can scroll down.
All you'd give to the form are objects of a data class like the one I showed, but without positioning data. They'd have a type, to figure out what kind of custom control to create, a description text, a default value to set the input control to, and possibly some kind of initialisation value, for example, to limit the range of a numeric value, or, as in the image I showed, values for a dropdown list.

How to create a progress bar with rounded corners in iOS using Xamarin.Forms

I used inputs from this SO Question to create a custom progress-bar with rounded corners for the Android platform using the Drawable.
But the I'm not able to create the same output for the iOS.
Given below is how it looks on Android.
How can I create the same effect in the iOS as well?
There are a number of ways to do this, I prefer using the CALayer of a UIView and adding a CAShapeLayer that draws the "progress bar".
UIView ProgressBar Example:
public class ProgressView : UIView
{
CAShapeLayer progressLayer;
UILabel label;
public ProgressView() { Setup(); }
public ProgressView(Foundation.NSCoder coder) : base(coder) { Setup(); }
public ProgressView(Foundation.NSObjectFlag t) : base(t) { Setup(); }
public ProgressView(IntPtr handle) : base(handle) { }
public ProgressView(CGRect frame) : base(frame) { Setup(); }
void Setup()
{
BackgroundColor = UIColor.Clear;
Layer.CornerRadius = 25;
Layer.BorderWidth = 10;
Layer.BorderColor = UIColor.Blue.CGColor;
Layer.BackgroundColor = UIColor.Cyan.CGColor;
progressLayer = new CAShapeLayer()
{
FillColor = UIColor.Red.CGColor,
Frame = Bounds
};
Layer.AddSublayer(progressLayer);
label = new UILabel(Bounds)
{
TextAlignment = UITextAlignment.Center,
TextColor = UIColor.White,
BackgroundColor = UIColor.Clear,
Font = UIFont.FromName("ChalkboardSE-Bold", 20)
};
InsertSubview(label, 100);
}
double complete;
public double Complete
{
get { return complete; }
set { complete = value; label.Text = $"{value * 100} %"; SetNeedsDisplay(); }
}
public override void Draw(CGRect rect)
{
base.Draw(rect);
var progressWidth = (rect.Width - (Layer.BorderWidth * 2)) * complete;
var progressRect = new CGRect(rect.X + Layer.BorderWidth, rect.Y + Layer.BorderWidth, progressWidth, (rect.Height - Layer.BorderWidth * 2));
progressLayer.Path = UIBezierPath.FromRoundedRect(progressRect, 25).CGPath;
}
}
Usage Example:
var progressView = new ProgressView(new CGRect(50, 50, 300, 50));
Add(progressView);
DispatchQueue.MainQueue.DispatchAsync(async () =>
{
while (progressView.Complete <= 1)
{
InvokeOnMainThread(() => progressView.Complete += 0.05);
await Task.Delay(1000);
}
});

Retrieving Data from a dynamic WPF form

I'm having some trouble with my WPF Form.
I have a list of objects, those objects have properties for Name, Value, IsRequired, Type (either bool, string or Datepicker).
So my list could have any number of objects and they could be either bool string etc.
I have created a custom control that propagates through this list and builds the form with the relevant controls such as CheckBox if its a bool and TextBox if its a string.
So far the code i have to generate this is like so, I have placed the controls in a grid for layout.
private object GetCustomElement(DicomMetadataModel metadata)
{
Grid dynamicGrid = new Grid() { VerticalAlignment = VerticalAlignment.Center };
dynamicGrid.Background = new SolidColorBrush(Colors.Transparent);
// Margin order LTRB
dynamicGrid.Margin = new Thickness(10, 3, 10, 3);
// Grid Definitions
ColumnDefinition col1 = new ColumnDefinition();
col1.Width = new GridLength(2, GridUnitType.Star);
ColumnDefinition col2 = new ColumnDefinition();
col2.Width = new GridLength(5, GridUnitType.Star);
RowDefinition gridRow1 = new RowDefinition();
gridRow1.Height = new GridLength(47);
dynamicGrid.ColumnDefinitions.Add(col1);
dynamicGrid.ColumnDefinitions.Add(col2);
dynamicGrid.RowDefinitions.Add(gridRow1);
//Label
var label = new Label()
{
FontSize = 15,
MinHeight = 12,
VerticalContentAlignment = VerticalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Margin = new Thickness(0),
Foreground = new SolidColorBrush(_lblTextColor)
};
label.Content = new TextBlock() { TextWrapping = TextWrapping.WrapWithOverflow, Text = metadata.Label };
Grid.SetRow(label, 0);
Grid.SetColumn(label, 0);
dynamicGrid.Children.Add(label);
if (metadata.Type == typeof(string) || metadata.Type == typeof(int))
{
//Textbox
var textBox = new TextBox()
{
MinWidth = 150,
MinHeight = 20,
Padding = new Thickness(5),
FontSize = 16,
Foreground = new SolidColorBrush(_lblTextColor),
BorderBrush = new SolidColorBrush(_tbBorderColor),
Background = new SolidColorBrush(_tbBackgroundColor)
};
textBox.IsReadOnly = IsReadOnly;
Grid.SetRow(textBox, 0);
Grid.SetColumn(textBox, 1);
dynamicGrid.Children.Add(textBox);
}
else if (metadata.Type == typeof(bool))
{
//RadioButton
var stack = new WrapPanel();
var view = new Viewbox() { MaxWidth = 30, Margin = new Thickness(10) };
var radioButton = new RadioButton()
{
Background = new SolidColorBrush(_tbBackgroundColor),
BorderBrush = new SolidColorBrush(_tbBorderColor),
BorderThickness = new Thickness(1),
Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FF7373"))
};
view.Child = radioButton;
stack.Children.Add((UIElement)view);
Grid.SetRow(stack, 0);
Grid.SetColumn(stack, 1);
dynamicGrid.Children.Add(stack);
}
return dynamicGrid;
}
This code is to create each element, this is recursively called in the following method
private void LoadViewerStudyInformation()
{
var dicomMetadata = DataContext as List<DicomMetadataModel>;
if (dicomMetadata == null)
{
throw new InvalidOperationException();
}
int count = 0;
foreach (var metadata in dicomMetadata)
{
if (!metadata.IsVisible)
{
continue;
}
else if(count < 5)
{
Children.Add((UIElement)GetCustomElement(metadata));
count++;
}
Margin = new Thickness(10);
Orientation = Orientation.Vertical;
}
// TODO build control, bind field to DataContext models
// TODO how result of control is bound to DataContext model Result property
}
This creates the the form as i would like it to appear on the screen.
I am having trouble now however hooking up the data entered and binding it to some model to store the information off.
I can hook up to the textbox TextChanged events but when it is fired there is not indication as to what property it should store to.
Will i need to create a new class say that has maybe a textbox and label property in it and call it like so , myClass.Textbox.Text etc.
MetaDataDicomModel here is like so
public class DicomMetadataModel
{
public string Value { get; set; }
public string Label { get; set; }
public Type Type { get; set; }
public bool IsRequired { get; set; }
public bool IsVisible { get; set; }
public bool IsReadOnly { get; set; }
}
I don't want to create something overly complicated because of a lack of understanding, if anyone could suggest the best way to do it i would be very grateful.

Carousel Page Indicator

I have a Xamarin.Forms (1.4.2.6359) Project using Visual Studio 2013 and have created the carousel page below. I want to add page indicators, i.e. dots over top of the carousel page. Is this able to be done with the Xamarin Forms CarouselPage?
public class SplashPage : CarouselPage
{
public SplashPage ()
{
this.Children.Add(new CarouselChild("Logo.png", "Welcome"));
this.Children.Add(new CarouselChild("Settings.png", "Settings"));
}
}
class CarouselChild : ContentPage
{
public CarouselChild(string image, string text)
{
StackLayout layout = new StackLayout
{
HorizontalOptions = LayoutOptions.CenterAndExpand,
VerticalOptions = LayoutOptions.CenterAndExpand,
};
layout.Children.Add(new Image
{
Source = image,
});
layout.Children.Add(new Label
{
HorizontalOptions = LayoutOptions.CenterAndExpand,
VerticalOptions = LayoutOptions.EndAndExpand,
Text = text,
Scale = 2,
});
this.Content = layout;
}
}
Trying to keep things simple, what I did was:
MyCarouselPage:
class MyCarouselPage : CarouselPage
{
private int totalPages;
private int currentPage;
public MyCarouselPage()
{
var pages = GetPages();
totalPages = pages.Length;
this.ChildAdded += MyCarouselPage_ChildAdded;
for (int i = 0; i < totalPages; i++)
{
currentPage = i;
this.Children.Add(pages[i]);
}
}
void MyCarouselPage_ChildAdded(object sender, ElementEventArgs e)
{
var contentPage = e.Element as MyPageBase;
if (contentPage != null)
{
contentPage.FinalStack.Children.Add(new CarouselPageIndicator(currentPage, totalPages, "indicator.png", "indicator_emtpy.png"));
}
}
private MyPageBase[] GetPages()
{
var pages = new MyPageBase[] { new Page1(), new Page2() };
return pages;
}
}
The Base class for the Pages
class MyPageBase:ContentPage
{
public StackLayout FinalStack { get; set; }
}
CarouselPageIndicator
public class CarouselPageIndicator : StackLayout
{
public CarouselPageIndicator(int currentIndex, int totalItems, string sourceIndicator, string souceEmptyIndicator)
{
this.Orientation = StackOrientation.Horizontal;
this.HorizontalOptions = LayoutOptions.CenterAndExpand;
for (int i = 0; i < totalItems; i++)
{
var image = new Image();
if (i == currentIndex)
image.Source = sourceIndicator;
else
image.Source = souceEmptyIndicator;
this.Children.Add(image);
}
this.Padding = new Thickness(10);
}
}
And for the n-Pages
class Page1:MyPageBase
{
public Page1()
{
var layout = new StackLayout
{
Children = {
new Label{Text="Page 1"}
}
};
this.FinalStack = layout;
this.Content = FinalStack;
}
}
I was able to make a work around for the problem by hard coding the page indicators by changing CarouselChild method below:
public CarouselChild(string image, string text, int pageNumber, int pageCount)
{
var width = this.Width;
StackLayout layout = new StackLayout
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
Padding = new Thickness( 40, 40, 40, 40),
BackgroundColor = Color.Black,
};
layout.Children.Add(new Image
{
Source = image,
VerticalOptions = LayoutOptions.Start,
HorizontalOptions = LayoutOptions.Center,
});
layout.Children.Add(new Label
{
HorizontalOptions = LayoutOptions.CenterAndExpand,
Text = text,
FontSize = 36,
LineBreakMode = LineBreakMode.WordWrap,
});
layout.Children.Add(CarouselPageIndicator(pageNumber, pageCount));
this.Content = layout;
}
internal StackLayout CarouselPageIndicator(int pageNumber, int pageCount)
{
StackLayout layout = new StackLayout
{
Orientation = StackOrientation.Horizontal,
HorizontalOptions = LayoutOptions.CenterAndExpand,
VerticalOptions = LayoutOptions.EndAndExpand,
};
if (pageCount >= pageNumber)
{
for (int i = 1; i < pageCount + 1; i++)
{
if (i == pageNumber)
{
layout.Children.Add(new Image
{
Source = "Light.png",
});
}
else
{
layout.Children.Add(new Image
{
Source = "Dark.png",
});
}
}
}
return layout;
}

Categories

Resources