Unable to add Rows dynamically to a Grid in WPF - c#

I want to add RowDefinitions to a Grid named notices. I could get the number of rows in the database and iterate those number of times, but I am unable to add the controls to a row.
The row is getting created, but StackPanel is not getting added. My code wants to create rows dynamically and to that a StackPanel and to the StackPanel a label and Image. In the .xaml file, I have only added the Grid.
How can I add a Row with StackPanel to the Grid?
This is my code:
StackPanel sp;
Label dt_label;
Image img;
BitmapImage bitmap;
string col1=null, col2 = "Picture_Path";
string Picture_Path=null;
RowDefinition gridRow1;
DateTime time;
for (int row_num = 0; row_num < No_Of_Rows; row_num++)
{
DataRow row = dt1.Rows[row_num];
foreach (object item in row.ItemArray)
{
gridRow1 = new RowDefinition();
sp = new StackPanel();
sp.Background = new SolidColorBrush(Colors.Yellow);
col1 = "Date_Time".ToString(); ;
time = DateTime.Parse(dt1.Rows[row_num][col1].ToString());
dt_label = new Label();
dt_label.Content = time;
Picture_Path = dt1.Rows[row_num][col2].ToString();
img = new Image();
bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri(Picture_Path, UriKind.Relative);
bitmap.EndInit();
img.Source = bitmap;
img.Height = 100;
img.Width = 100;
sp.Children.Add(dt_label);
sp.Children.Add(img);
notices.RowDefinitions.Add(gridRow1);
break;
}
}
}
catch (Exception ex)
{
MessageBox.Show("ERROR \n" + ex.ToString());
}

You must set attached properties (Grid.Row and Grid.Column) to your controls using Grid.SetRow and Grid.SetColumn.
After this you need to add control to grid like this:
nameOfYourGrid.Children.Add(nameOfYourControl);
Also, there are some interesting lines in your code:
"Date_Time".ToString(); ;
Why are you converting string to a string?
Majority of fields can be moved to inner foreach scope.

Related

Retreive stackpanel children from GridViewItem (UWP)

I'm wondering how I can get the contents of a stackpanel which has been added to a GridViewItem (YouTube data API, the stackpanel contains a bitmap image for a thumbnail, the title of the video and a hidden TextBlock with the video ID for reference).
To clarify, I need to be able to obtain the contents of the StackPanel that is contained in the GridViewItem (such as the string of that hidden TextBox) so I can use the data to display the correct video.
Here's the code I use to create the stackpanel.
public async Task SearchByKeyword(string searchTerm)
{
GeneralFunctions gf = new GeneralFunctions();
var youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
ApiKey = gf.YouTubeAPIKey,
ApplicationName = this.GetType().ToString()
});
var searchListRequest = youtubeService.Search.List("snippet");
searchListRequest.Q = searchTerm; // Replace with your search term.
searchListRequest.MaxResults = 50;
searchListRequest.SafeSearch = SearchResource.ListRequest.SafeSearchEnum.Strict;
// Call the search.list method to retrieve results matching the specified query term.
var searchListResponse = await searchListRequest.ExecuteAsync();
List<string> videos = new List<string>();
List<string> channels = new List<string>();
List<string> playlists = new List<string>();
// Add each result to the appropriate list, and then display the lists of
// matching videos, channels, and playlists.
foreach (var searchResult in searchListResponse.Items)
{
switch (searchResult.Id.Kind)
{
case "youtube#video":
// Create a new StackPanel to insert as a ListViewItem
StackPanel sPanel = new StackPanel();
sPanel.HorizontalAlignment = HorizontalAlignment.Stretch;
sPanel.VerticalAlignment = VerticalAlignment.Stretch;
sPanel.Orientation = Orientation.Vertical;
sPanel.Width = 160;
sPanel.Height = 160;
// Create new StackPanel "Child" elements with alignment and width
TextBlock tb1 = new TextBlock();
tb1.Text = searchResult.Snippet.Title;
tb1.TextWrapping = TextWrapping.WrapWholeWords;
tb1.Width = 160;
// Create new StackPanel "Child" elements with alignment and width
TextBlock tb2 = new TextBlock();
tb2.Text = searchResult.Snippet.ChannelId;
tb2.TextWrapping = TextWrapping.WrapWholeWords;
tb2.Width = 160;
// Create new StackPanel child element for a 120x120 thumbnail of the videos from the search results
Image image = new Image();
image.Source = new BitmapImage(new Uri(searchResult.Snippet.Thumbnails.Default__.Url, UriKind.Absolute));
// Add a "hidden" child element to each stackpanel to hold the video identity
TextBlock h1 = new TextBlock();
h1.Text = searchResult.Id.VideoId.ToString();
h1.Visibility = Visibility.Collapsed;
h1.TextWrapping = TextWrapping.WrapWholeWords;
sPanel.Children.Add(image);
sPanel.Children.Add(tb1);
sPanel.Children.Add(tb2);
sPanel.Children.Add(h1);
SearchResults.Items.Add(sPanel);
break;
case "youtube#channel":
//SearchResults.Items.Add(String.Format("{0} ({1})", searchResult.Snippet.Title, searchResult.Id.ChannelId));
break;
case "youtube#playlist":
//playlists.Add(String.Format("{0} ({1})", searchResult.Snippet.Title, searchResult.Id.PlaylistId));
break;
}
}
//Console.WriteLine(String.Format("Videos:\n{0}\n", string.Join("\n", videos)));
//Console.WriteLine(String.Format("Channels:\n{0}\n", string.Join("\n", channels)));
//Console.WriteLine(String.Format("Playlists:\n{0}\n", string.Join("\n", playlists)));
}
Any help is appreciated.
Thanks
I guess I should never code tired right? The answer to my own question is actually very very simple
if (SearchResults.SelectedItems.Count > 0)
{
StackPanel sp = (StackPanel)SearchResults.SelectedItem;
TextBlock tb1 = (TextBlock)sp.Children[1];
TextBlock tb2 = (TextBlock)sp.Children[2];
TextBlock hf1 = (TextBlock)sp.Children[3];
}

Listview items and Image list items missmatching

I have created a image grid view using ListView and ImageList.. image names come from database and images are stored in categories folder. I adding images imgList.Images.Add("", Image.FromFile(#"./categories/" + dr["image"]));
but when program runs 1st list view item not set to the correct image, 1stlistviewitem with second image, i think there is a indexing error. is something wrong with my code or any way to solve this?
private void LoadCategories() {
DataTable categories;
con = new Dbfunctions();
con.MysqlQuery("SELECT * FROM categories WHERE online = 1");
categories = con.QueryEx();
//ImageList
ImageList imgList = new ImageList();
//CLEAR listview_Category items
listView_Category.Items.Clear();
//set listview category items as Large icons
listView_Category.View = View.LargeIcon;
//ADD image list into Listview
listView_Category.LargeImageList = imgList;
int i = 0;
//ADD image into imagelist and Listview
foreach(DataRow dr in categories.Rows){
imgList.Images.Add("", Image.FromFile(#"./categories/" + dr["image"]));
ListViewItem category = new ListViewItem();
//bind listview item vwith image list item
category.ImageIndex = i;
//set Category name
category.Text = dr["name"].ToString();
//set font list items styles
category.Font = new System.Drawing.Font("Courier New", 15, System.Drawing.FontStyle.Regular);
category.ForeColor = System.Drawing.Color.FromArgb(252, 119, 123);
//ADD category items into Listview
listView_Category.Items.Add(category);
imgList.ImageSize = new Size(140, 140);
imgList.ColorDepth = ColorDepth.Depth32Bit;
i++;
}
}
Please provide shapes of DB rows. Maybe you have a missmatch in DB so you call not proper index.

Create a Details Form from a GridView c#

Possibly a complex question - but here's hoping
I have a generic data grid on a single form (displays whatever table I want from a dataset) simply by swapping tables in the dataset.
I want to double-click on a given record and display a single-record view of the table data with the currently selected record displayed as default, but with the option to page through and edit/view/delete other records i.e.
I want to automatically create a details view form from a datagrid for a given table at runtime. The form should be dynamically created - displaying the dataset in details view with the option to page through single records using the binding source/binding source navigator.
My goal is to improve efficiency/maintainability of the application - rather than create and manage 10+ forms, I simply want to create and manage I generic details form in the same way as I manage I generic gridview form.
So far I have come up with:
public void CreateDetailsForm(BindingSource bs, int rowClicked)
{
Form detailsForm = new Form();
BindingSource newFormBS = new BindingSource();
//assign binding source for use on new detailsForm
newFormBS = bs;
//assign binding source to datatable
DataTable dt = (DataTable)bs.DataSource;
//create the form fields
CreateFormFields(dt); //not yet implemented
//assign form fields to form
//display form
}
Any help on the following appreciated
Generating and assigning the form fields to the form.
Thanks in advance.
it likes:
Form f=new Form();
TextBox t=new TextBox();//generate the controls u need
t.Text = "test";//set the actual value
t.Location=new Point(10,10);
f.Controls.Add(t);
DialogResult dr=f.ShowDialog();
So far I have got the col names generated on the form as follows
List colNames = GetColumnNames(dt);
int offset=25;
int xPos=50;
int yPos = 10;
foreach (string name in colNames)
{
Label l = new Label();
l.Name = name;
l.Width = 200;
l.Text = name;
TextBox t = new TextBox();
t.Name = name;
t.Width=200;
l.Location = new Point(xPos, yPos );
t.Location = new Point(xPos+250, yPos);
f.Controls.Add(l);
f.Controls.Add(t);
yPos = yPos + offset;
}
//TextBox t = new TextBox();//generate the controls u need
//t.Text = "test";//set the actual value
f.Width = 800;
f.Height = 600;
f.Show();
}
private List<string> GetColumnNames(DataTable table)
{
List<string> lstColNames=new List<string>();
if (table != null)
{
lstColNames=
(from DataColumn col in table.Columns
select col.ColumnName).ToList();
}
return lstColNames;
}
Now trying to work on getting the controls to bind to the binding source!
OK - got it working now - had to take a different approach
Created a single detailsView Form
Created a static class called PassBindingSource with a static property bst for passing binding source from gridview to details form
static class PassBindingSource
{
public static BindingSource bst { get; set; }
}
On the detailsView form added the following code
try{ bs.DataSource = PassBindingSource.bst;
DataTable dt = (DataTable)PassBindingSource.bst.DataSource;
List<string> colNames = GetColumnNames(dt);
int offset = 25;
int xPos = 50;
int yPos = 50;
foreach (string name in colNames)
{
Label l = new Label();
l.Name = name;
l.Width = 200;
l.Text = name;
TextBox t = new TextBox();
t.Name = name;
t.Width = 200;
// BindingOperations.SetBinding(t, t.TextProperty, bs);
//binding operation
t.DataBindings.Add(new Binding("Text", bs, t.Name, true));
l.Location = new Point(xPos, yPos);
t.Location = new Point(xPos + 250, yPos);
this.Controls.Add(l);
this.Controls.Add(t);
yPos = yPos + offset;
// dgDetailsView.DataSource = bs;
}
//move to correct record in binding source
bs.Position = PassBindingSource.currentRecord;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private List<string> GetColumnNames(DataTable table)
{
List<string> lstColNames=new List<string>();
if (table != null)
{
lstColNames=
(from DataColumn col in table.Columns
select col.ColumnName).ToList();
}
return lstColNames;
}
SUMMARY
Now it all works - the detailsView controls generated at run-time wired up correctly to the binding source and the datagrid can call this detailsView any time using any table from the dataset by wiring the double-click event of the gridview with the following code
PassBindingSource.bst= bs;
frmDetailsView nf = new frmDetailsView();
nf.Show();
Hope this helps others. Many thanks to User2354374 for the initial steer.

How to retrieve the name of a Panorama-Item at runtime?

I am programmatically adding items to my Panorama Control called PanoramaCC.
//function to create the panorama items in our view
private void showPanorama(string panoramaName)
{
//create the panorama item and define it
PanoramaItem genItem = new PanoramaItem();
genItem.Height = 265;
genItem.Width = 440;
genItem.Tap += new EventHandler<System.Windows.Input.GestureEventArgs>(PanoramaItem_Tap);
genItem.Name = panoramaName;
//create the stackpanel for the panoramaitem
StackPanel genStack = new StackPanel();
genStack.Orientation = System.Windows.Controls.Orientation.Horizontal;
//margin to be done
genStack.Margin = new Thickness(0, -20, 0, 20);
//load the image
Image genImg = new Image();
genImg.Height = 220;
genImg.Width = 400;
genImg.Stretch = System.Windows.Media.Stretch.Fill;
genImg.Margin = new Thickness(20, 5, 20, 5);
string path = "Assets/AppGraphics/CreditCards/" + panoramaName.ToString() + "Front.png";
Uri uriR = new Uri(path, UriKind.Relative);
BitmapImage imgSource = new BitmapImage(uriR);
genImg.Source = imgSource;
//add image into stackpanel
genStack.Children.Add(genImg);
//add stackpanel to the panoramaitem
genItem.Content = genStack;
//add the panoramaitem to the panoramaview
this.PanoramaCC.Items.Add(genItem);
}
The issue I have is that during runtime I want to retrieve the name of the panoramaItem I am currently looking at and do something with it. I've managed to retrieve the name through the tap event for navigation purposes, string name = ((PanoramaItem)sender).Name; but this is a diffrent scenario. I want to retrieve the name and then delete the item with the corresponding name. Pressing a button should delete the currently selected panoramaItem, is what I'm trying to achieve.
You can get the current PanoramaItem by using the SelectedItem property. You don't need to get the name to delete it.
PanoramaItem currentItem = myPanorama.SelectedItem as PanoramaItem;
if(currentItem != null)
{
//if you want the name for other reasons
string name = currentItem.Name;
//Items returns an ItemsCollection object
myPanorama.Items.Remove(currentItem);
}

sort stackpanel based on child elements?

Is there a way to order stackpanels based on some of its child elements?
In the code behind I add some generic things like groupbox and textblock to a stackpanel, one of the textblocks information is DateTime from my webservice, I have tryed sorting via descending order using linq but the output is still the same.
So I was wondering if its possible to sort by one of the stackpanels child elements namely the textblock1.Text that holds the DateTime attribute?
XDocument xDoc = XDocument.Load(uriGroups);
var sortedXdoc = xDoc.Descendants("Student")
.OrderByDescending(x => Convert.ToDateTime(x.Element("TimeAdded").Value));
foreach (var node in xDoc.Descendants("Student"))
{
GroupBox groupbox = new GroupBox();
groupbox.Header = String.Format(node.Element("StudentID").Value);
groupbox.Width = 100;
groupbox.Height = 100;
groupbox.Margin = new Thickness(1);
TextBlock textBlock = new TextBlock();
textBlock.Text = String.Format(node.Element("FirstName").Value + " " + (node.Element("LastName").Value));
textBlock.TextAlignment = TextAlignment.Center;
TextBlock textBlock1 = new TextBlock();
textBlock1.Text = (DateTime.Parse(node.Element("TimeAdded").Value)).ToString("d");
String.Format("{0:d/M/yyyy}", DateTime.Parse(node.Element("TimeAdded").Value));
textBlock1.TextAlignment = TextAlignment.Center;
textBlock1.VerticalAlignment = VerticalAlignment.Bottom;
StackPanel stackPanel = new StackPanel();
stackPanel.Children.Add(groupbox);
stackPanel.Children.Add(textBlock);
stackPanel.Children.Add(textBlock1);
stackPanel.Margin = new Thickness(5);
stackPanel.MouseEnter += new MouseEventHandler(stackpanel_MouseEnter);
stackPanel.MouseLeave += new MouseEventHandler(stackpanel_MouseLeave);
MainArea1.Children.Add(stackPanel);
}
}
The order of display is totally defined by the order of calls to
MainArea1.Children.Add(stackPanel);
So, try something like
foreach (var node in xDoc.Descendants("Student").OrderBy(e => ...))
{
....
}
(And you really should be using Temlates here)

Categories

Resources