Xamarin bind a dynamic list of images to a grid - c#

first of all sorry for the mess, I'm kicking my head in this for a while already, I'm kind new in xamarin and starting with difficult problems. I'm trying to add dynamically a list of random images in a grid.
currently i have the grid printing like
Name1 Detail1
filename1 filename2 filename3
Name2 Detail2
Filename1 filename2
var cell = new DataTemplate(() => {
var grid = new Grid() { Padding = 8, RowSpacing = 5, ColumnSpacing = 5 };
grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) });
grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Star) });
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) });
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(50, GridUnitType.Star) });
Subtitle.SetBinding(Label.TextProperty, "Images");
grid.Children.Add(labelName, 0, 0);
grid.Children.Add(labelDetail, 1, 0);
grid.Children.Add(Subtitle, 1, 1);
the cell in the end is attached to a listview
listdata.ItemTemplate = cell;
in the Object I have defined images as a string, I already tried to create another bind to a list, and create a listview of a custom call and add it to the grid, but throws an error and I can't see any description, it's something like sigsegv-without-stack trace
Also tried to instead of a grid, create a stack layout. again nothing.
CustomCell
public class CustomNocCell : ViewCell
{
public CustomCell()
{
//instantiate each of our views
var image = new Image();
var nameLabel = new Label();
var typeLabel = new Label();
var verticaLayout = new StackLayout();
var horizontalLayout = new StackLayout() { BackgroundColor = Color.Transparent };
//set bindings
nameLabel.SetBinding(Label.TextProperty, new Binding("Name"));
image.SetBinding(Image.SourceProperty, new Binding("Image"));
//Set properties for desired design
horizontalLayout.Orientation = StackOrientation.Horizontal;
horizontalLayout.HorizontalOptions = LayoutOptions.Center;
image.HorizontalOptions = LayoutOptions.End;
nameLabel.FontSize = 24;
//add views to the view hierarchy
verticaLayout.Children.Add(nameLabel);
horizontalLayout.Children.Add(verticaLayout);
horizontalLayout.Children.Add(image);
// add to parent view
View = horizontalLayout;
}
}
what I tried already that gave the error
//ListView listView = new ListView();
//listView.RowHeight = 60;
//listView.ItemTemplate = new DataTemplate(typeof(CustomNocCell));
////listView.ItemsSource = "ImagesNoc";
//listView.SetBinding(ListView.ItemsSourceProperty, "ImagesList");
ImagesList class
[Ignore]
public ListView ImagesList
{
get
{
ListView listView = new ListView();
listView.RowHeight = 60;
listView.ItemTemplate = new DataTemplate(typeof(CustomNocCell));
List<string> list = new List<string>();
if (!string.IsNullOrEmpty(Detail))
{
foreach (string str in Detail.Split(';'))
{
list.Add(str);
}
}
listView.ItemsSource = list.Select(s => new { Name = s, Image = s.ToLower() + ".png" }).ToList();
return listView;
}
}
I had the class also returning a simple List of type Name and Image that the CustomCell is waiting and nothing.
EDIT
public class TestObject
{
public string title { get; set; }
public string countries { get; set; }
}
void load()
{
List<TestObject> list = new List<TestObject>();
list.Add(new TestObject { title = "test1", countries = "esp,ita,prt" });
list.Add(new TestObject { title = "test2", countries = "esp,ita" });
list.Add(new TestObject { title = "test3", countries = "rus" });
var labelTitle = new Label()
{
FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label)),
VerticalOptions = LayoutOptions.StartAndExpand,
};
listdata = new ListView();
listdata.ItemsSource = list;
var cell = new DataTemplate(() => {
var grid = new Grid() { Padding = 8, RowSpacing = 5, ColumnSpacing = 5 };
grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) });
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) });
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) });
labelTitle.SetBinding(Label.TextProperty, "title");
countriesLabel.SetBinding(Label.TextProperty, "countries"); //here i want to make a customcell to show the images, like be able to "bind" and calc the countries split the string by "," and add (name + ".png") then show the image.
// i was able to do it in a listview when i have the source in my side.. in this one i have to bind and then calc..
grid.Children.Add(labelTitle, 0, 0);
grid.Children.Add(countriesLabel, 1, 0);
});
listdata.ItemTemplate = cell;
}

Related

How can i create N grid row ? In Xamarin/C#

I have a project. I have a table. ( Made from grid ) And i have a entry/Textbox. I need make like customer will write number to entry ( Lets call that number "n" ). Then i need add n row inside of my table made from grid. How can i do that ?
Its my codes for make grid table.
gr.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(1, GridUnitType.Absolute)
});
gr.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(1, GridUnitType.Star)
});
gr.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(1, GridUnitType.Absolute)
});
gr.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(1, GridUnitType.Star)
});
gr.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(1, GridUnitType.Absolute)
});
gr.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(1, GridUnitType.Star)
});
gr.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(1, GridUnitType.Absolute)
});
gr.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(1, GridUnitType.Star)
});
gr.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(1, GridUnitType.Absolute)
});
gr.ColumnDefinitions.Add(new ColumnDefinition
{
Width = new GridLength(1, GridUnitType.Absolute)
});
gr.ColumnDefinitions.Add(new ColumnDefinition
{
Width = new GridLength(1, GridUnitType.Star)
});
gr.ColumnDefinitions.Add(new ColumnDefinition
{
Width = new GridLength(1, GridUnitType.Absolute)
});
gr.ColumnDefinitions.Add(new ColumnDefinition
{
Width = new GridLength(1, GridUnitType.Star)
});
gr.ColumnDefinitions.Add(new ColumnDefinition
{
Width = new GridLength(1, GridUnitType.Absolute)
});
var backgroundbox = new BoxView
{
Color = System.Drawing.Color.FromArgb(-32513)
};
gr.Children.Add(backgroundbox, 0, 1);
Grid.SetColumnSpan(backgroundbox, 5);
var ustyatay = new BoxView { Color = System.Drawing.Color.Gray };
gr.Children.Add(ustyatay, 0, 0);
Grid.SetColumnSpan(ustyatay, 5);
var yatay2 = new BoxView { Color = System.Drawing.Color.Gray };
gr.Children.Add(yatay2, 0, 2);
Grid.SetColumnSpan(yatay2, 5);
var yatay3 = new BoxView { Color = Xamarin.Forms.Color.Gray };
gr.Children.Add(yatay3, 0, 4);
Grid.SetColumnSpan(yatay3, 5);
var yatay4 = new BoxView { Color = Xamarin.Forms.Color.Gray };
gr.Children.Add(yatay4, 0, 6);
Grid.SetColumnSpan(yatay4, 5);
var soldik = new BoxView { Color = System.Drawing.Color.Gray };
gr.Children.Add(soldik, 0, 0);
Grid.SetRowSpan(soldik, 7);
var ortadik = new BoxView { Color = Xamarin.Forms.Color.Gray };
gr.Children.Add(ortadik, 2, 0);
Grid.SetRowSpan(ortadik, 7);
var sagdik = new BoxView { Color = System.Drawing.Color.Gray };
gr.Children.Add(sagdik, 4, 0);
Grid.SetRowSpan(sagdik, 7);
gr.Children.Add(new Label
{
Text = "Customer Name",
FontAttributes = FontAttributes.Bold,
TextColor = System.Drawing.Color.Yellow,
FontSize = 16,
Padding=new Thickness(10,10)
}, 1, 1); ;
gr.Children.Add(new Label
{
Text = "T.Type Name",
FontAttributes = FontAttributes.Bold,
TextColor= Xamarin.Forms.Color.Yellow,
FontSize=16,
Padding = new Thickness(10, 10)
}, 3, 1);
I made lines as grid column,row too. I think i made it wrong. When i add n row i need change rowspan too. Idk how can i make that project. Can you guys help me please ? I need learn : How can i add rows with entry , how can i add boxview and rowspan for new row (For make line) ? Thanks for help guys!
That photo for what should i do with my hand drawing : https://prnt.sc/10jxdhn
I can slove the problem by using Data binding.
First, edit your .xaml file like this:
<Entry Text="{Binding N}"></Entry>
<Button Text="Create" Command ="{Binding CreateCommand}"></Button>
<ListView ItemsSource="{Binding Rows}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Label Text="{Binding}"></Label>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Next create a ViewModel, I call it Page1ViewModel.cs.
In .xaml.cs file, add the binding context to Page1ViewModel in the constructor
BindingContext = new Page1ViewModel();
In Page1ViewModel.cs:
class Page1ViewModel : INotifyPropertyChanged
{
private int n;
private List<string> rows;
public List<string> Rows
{
get => rows;
set
{
rows = value;
OnPropertyChanged();
}
}
public int N
{
get => n;
set
{
n = value;
OnPropertyChanged();
}
}
public Command CreateCommand { get; }
public Page1ViewModel()
{
Rows = new List<string>();
CreateCommand = new Command(Create);
}
private void Create()
{
List <string> tmp = new List<string>();
for (int i = 0; i < n; i++)
{
tmp.Add("Row" + i);
}
Rows = tmp;
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
Good luck!

Show grids in Xamarin forms from code behind(c#)

I have some data which is received as response from rest api. I need to display this data in a grid form.
Json is as follow:
{
"field 1" : "name1",
"field 2" : "name 2",
"data" : [
{
"type 1" : "name 1",
"type 2" : "name 2"
},
{
"type 1" : "name 3",
"type 2" : "name 4"
}
]
So, from the above sample the number of entries in "data" field may vary dynamically. I creating a grid to display these fields from code behind as follows:
foreach(var obj in data) //reads data fields
{
//json deserialization goes here
Grid grid = new Grid() //want to create a separate grid for each entry in json *data*
{
VerticalOptions = LayoutOptions.Start,
RowDefinitions =
{
new RowDefinition { Height = GridLength.Auto },
new RowDefinition { Height = GridLength.Auto },
},
};
grid.Children.Add(new Label
{
Text = "Field 1",
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
HorizontalOptions = LayoutOptions.Center
}, 0, 0);
///more code on grid.
}
From the above implementation, only a single grid is created which has entries for last value of data field (i.e, name3, name4). How do I display separate grids for each json nested fields in data
You could try the code below. I use json string for example. Use a boxview to split the column name and data. You could use boxview to split data as well.
public ObservableCollection<Rootobject> list { get; set; }
public MainPage()
{
InitializeComponent();
var datas = #"{
'field1':'name1',
'field2':'name2',
'data':[
{
'type1':'name1',
'type2':'name2'
},
{
'type1':'name3',
'type2':'name4'
}
]
}";
var jsondata = JsonConvert.DeserializeObject<Rootobject>(datas);
list = new ObservableCollection<Rootobject>();
list.Add(jsondata);
Grid grid = new Grid() { RowSpacing = 5, ColumnSpacing = 5, };
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
var field1 = new Label()
{
Text = "field1",
VerticalOptions = LayoutOptions.Center
};
var field2 = new Label()
{
Text = "field2",
VerticalOptions = LayoutOptions.Center
};
var data = new Label()
{
Text = "data",
HorizontalOptions = LayoutOptions.Center
};
var type1 = new Label()
{
Text = "type1",
};
var type2 = new Label()
{
Text = "type2",
};
var boxview = new BoxView()
{
BackgroundColor = Color.Black,
HeightRequest = 1
};
grid.Children.Add(field1, 0, 0);
Grid.SetRowSpan(field1, 2);
grid.Children.Add(field2, 1, 0);
Grid.SetRowSpan(field2, 2);
grid.Children.Add(data, 2, 0);
Grid.SetColumnSpan(data, 2);
grid.Children.Add(type1, 2, 1);
grid.Children.Add(type2, 3, 1);
grid.Children.Add(boxview, 0, 2);
Grid.SetColumnSpan (boxview,4);
foreach (var item in list)
{
var field1_value = new Label()
{
Text = item.field1,
};
grid.Children.Add(field1_value, 0, 3);
Grid.SetRowSpan(field1_value, 2);
var field2_value = new Label()
{
Text = item.field2,
};
grid.Children.Add(field2_value, 1, 3);
Grid.SetRowSpan(field2_value, 2);
int row_type1 = 3;
int row_type2 = 3;
foreach (var type_value in item.data)
{
var type1_value = new Label()
{
Text = type_value.type1,
};
grid.Children.Add(type1_value, 2, row_type1);
var type2_value = new Label()
{
Text = type_value.type2,
};
grid.Children.Add(type2_value, 3, row_type2);
row_type1++;
row_type2++;
}
}
Content = grid;
//this.BindingContext = jsondata;
}
}
public class Rootobject
{
public string field1 { get; set; }
public string field2 { get; set; }
public Datum[] data { get; set; }
}
public class Datum
{
public string type1 { get; set; }
public string type2 { get; set; }
}
}
you need to add your grids to a layout container
StackLayout stack = new StackLayout();
foreach(var obj in data) //reads data fields
{
Grid grid = new Grid()
{
...
}
stack.Children.Add(grid);
}

programatically binding a listview in xamarin c#

I want to create a listview in Xamarin portable,
the item source of the listview is List<String> and my datatemplate of the listview is prepared by this function,
private DataTemplate createItemtemplate()
{
try
{
Label lbl_binding = new Label()
{
TextColor = Color.Red,
FontSize = 16,
VerticalTextAlignment = TextAlignment.Center,
HorizontalOptions = LayoutOptions.CenterAndExpand,
};
lbl_binding.SetBinding(Label.TextProperty, ".");
StackLayout stkBottom = new StackLayout()
{
Orientation = StackOrientation.Horizontal,
HorizontalOptions = LayoutOptions.CenterAndExpand,
VerticalOptions = LayoutOptions.Center,
Padding = new Thickness(0),
};
stkBottom.Children.Add(lbl_binding);
ViewCell vc = new ViewCell() {
View = stkBottom
};
DataTemplate Dp = new DataTemplate(() =>
{
return vc;
});
return Dp;
}
catch (Exception ex)
{
return null;
}
}
Now, my list view is populated, but all the labels are filled with last item, I mean the no of items are rightly populated, but all the items are filled with the last item only.
what i am doing wrong here?
lstAdmin = new ListView()
{
ItemTemplate = createItemtemplate(),
};
lstadmin.Itemsource = source;
Change your listview from List to ObservableCollection. This should do the work.
Below code useful for you as reference
Take Class members:
public class Dummy
{
public string Id { get; set; }
public string Img { get; set; }
public string Title { get; set; }
public string SubTitle { get; set; }
public string Count { get; set; }
public string Status { get; set; }
}
Create One ObservableCollectionList:
ObservableCollection<Dummy> productItems = new
ObservableCollection<Dummy>();
Add Items to the ObservableCollectionList:
productItems.Add(new Dummy() { Name = "0", Img = "Avatar.png",
Title = "Total Books", SubTitle = "Desc", Count = "50", Status =
"Total" });
productItems.Add(new Dummy() { Id = "1", Img = "Avatar.png", Title
= "Out of Stock Books", SubTitle = "Desc", Count = "40", Status =
"OutStock" });
Declare ListView:
ListView listview = new ListView()
{
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
SeparatorVisibility = SeparatorVisibility.None,
RowHeight = 30,
};
listview.ItemTemplate = new DataTemplate(typeof(cell));
listview.ItemSelected += listviewItemSelected;
Take ViewCell and design your UI in ViewCell and assign binding
public class cell : ViewCell
{
public cell()
{
Image img = new Image()
{
VerticalOptions = LayoutOptions.StartAndExpand,
};
img.SetBinding(Image.SourceProperty, new Binding("Img"));
Label lbltitle = new Label()
{
VerticalOptions = LayoutOptions.Start,
TextColor = Color.Black
};
lbltitle.SetBinding(Label.TextProperty, new
Binding("Title"));
Label lbldesc = new Label()
{
VerticalOptions = LayoutOptions.Start,
TextColor = Color.Black
};
lbldesc.SetBinding(Label.TextProperty, new
Binding("SubTitle"));
StackLayout lblstack = new StackLayout()
{
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
Children = { lbltitle, lbldesc },
};
BoxView boxEdit = new BoxView()
{
VerticalOptions = LayoutOptions.Start,
HorizontalOptions = LayoutOptions.End,
Color = Color.Black,
HeightRequest = 20,
WidthRequest = 10
};
tapGestureEdit.Tapped += tapGestureEditTapped;
Label lblCount = new Label()
{
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
TextColor = Color.Black
};
lblCount.SetBinding(Label.TextProperty, new
Binding("Count"));
StackLayout stackCount = new StackLayout()
{
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.EndAndExpand,
Children = { boxEdit, lblCount },
};
StackLayout stackMain = new StackLayout()
{
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
Children = { img, lblstack, stackCount },
Orientation = StackOrientation.Horizontal,
Margin = new Thickness(10, 10, 10, 10)
};
View = stackMain;
}
}
public class AdminCell : ViewCell
{
public AdminCell()
{
Label lbl_binding = new Label()
{
TextColor = Color.FromRgb(30, 144, 255),
FontSize = 16,
VerticalTextAlignment = TextAlignment.Center,
HorizontalOptions = LayoutOptions.CenterAndExpand,
};
lbl_binding.SetBinding(Label.TextProperty, ".");
StackLayout stkBottom = new StackLayout()
{
Orientation = StackOrientation.Horizontal,
HorizontalOptions = LayoutOptions.CenterAndExpand,
VerticalOptions = LayoutOptions.Center,
Padding = new Thickness(0),
};
stkBottom.Children.Add(lbl_binding);
View = stkBottom;
}
}
this code is working for me removed the template and use this cell, i still don't understand why the data template is not working
I had the same issue and after some tests I've figured out how to not get always the last item.
You should put the Label creation ,and all the other elements you want put as ItemTemplate, inside the lambda of the DataTemplate like this (example code) :
DataTemplate itemTemplate = new DataTemplate(() =>
{
Label label = new Label()
{
Margin = new Thickness(45, 0, 0, 0),
HorizontalOptions = LayoutOptions.Start,
FontSize = (double)Xamarin.Forms.Application.Current.Resources["BodyFontSize"],
HeightRequest = 20
};
label.SetBinding(Label.TextProperty, "Name");
ViewCell templateCell = new ViewCell()
{
View = label
};
return templateCell;
});
Hope that helps (helped in my case).

Xamarin forms RelativeLayout not appearing

I am following some pretty standard Xamarin forms tutorials and I am really struggling to get the RelativeLayout to work. Ultimately I want to have an ActivityIndicator overlaid on top of the mainContent:
BindingContext = new LoginViewModel(this);
Padding = new Thickness(20);
Title = "Login";
var image = new Image
{
Source = ImageSource.FromFile("logo.png"),
HeightRequest = 50
};
var label = new Label
{
Text = "...",
FontSize = 20,
HorizontalTextAlignment = TextAlignment.Center
};
var errorLabel = new Label
{
Text = "",
TextColor = Color.Red,
FontSize = 20,
HorizontalTextAlignment = TextAlignment.Center
};
var loginButton = new Button
{
Text = "Log In",
BackgroundColor = Color.Black,
TextColor = Color.White,
FontSize = 20,
HeightRequest = 50
};
var loginEntry = new Entry
{
Placeholder = "Username"
};
var passwordEntry = new Entry
{
Placeholder = "Password"
};
var copywrite = new Label
{
Text = "© 2016",
FontSize = 15,
HorizontalTextAlignment = TextAlignment.Center
};
var loadingIndicator = new ActivityIndicator
{
BackgroundColor = Color.Blue,
IsVisible = true
};
...
var topLayer = new StackLayout
{
Spacing = 10,
Children = { image, label, loginEntry, passwordEntry, loginButton, errorLabel },
VerticalOptions = LayoutOptions.Start
};
var bottomLayer = new StackLayout
{
Spacing = 10,
Children = { copywrite },
VerticalOptions = LayoutOptions.End
};
var mainContent = new StackLayout
{
Children =
{
topLayer,
new StackLayout
{
VerticalOptions = LayoutOptions.CenterAndExpand,
},
bottomLayer
},
VerticalOptions = LayoutOptions.FillAndExpand,
BackgroundColor = Color.Green
};
var r = new RelativeLayout()
{
BackgroundColor = Color.Pink
};
r.Children.Add(mainContent,
Constraint.RelativeToParent((parent) =>
{
return parent.Width;
}),
Constraint.RelativeToParent((parent) =>
{
return parent.Height;
})
);
Content = r;
When I set Content = mainContent I see everything fine, but with the above code I get a white screen. I have been looking here.
When I try this:
var overlay = new AbsoluteLayout()
{
BackgroundColor = Color.Pink
};
AbsoluteLayout.SetLayoutFlags(mainContent, AbsoluteLayoutFlags.PositionProportional);
AbsoluteLayout.SetLayoutBounds(mainContent, new Rectangle(0f, 0f, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));
AbsoluteLayout.SetLayoutFlags(loadingIndicator, AbsoluteLayoutFlags.PositionProportional);
AbsoluteLayout.SetLayoutBounds(loadingIndicator, new Rectangle(0.5, 0.5, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));
overlay.Children.Add(mainContent);
overlay.Children.Add(loadingIndicator);
Content = overlay;
I can see the Green and Pink views, but they may as well be stacked (as opposed to being overlaid) - but also I cannot see the Activity Indicator inside the Pink Absolute layout.
For the RelativeLayout, the Add method you are calling is setting a constraint on X and Y, not on width and height. The order of the parameters for that variant of Add is:
Child View
X constraint
Y constraint
Width constraint
Height constraint
With all constraints being optional.
To explicitly place it over the entire screen, do something like this:
r.Children.Add(mainContent,
Constraint.Constant(0),
Constraint.Constant(0),
Constraint.RelativeToParent((parent) =>
{
return parent.Width;
}),
Constraint.RelativeToParent((parent) =>
{
return parent.Height;
})
);
For the AbsoluteLayout, try a slightly different set of constraints:
AbsoluteLayout.SetLayoutFlags(mainContent, AbsoluteLayoutFlags.All);
AbsoluteLayout.SetLayoutBounds(mainContent, new Rectangle(0f, 0f, 1f, 1f));
This explicitly specifies that mainContent is to occupy the entire AbsoluteLayout rather than relying on the actual layout size of mainContent.

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.

Categories

Resources