473,320 Members | 1,930 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

Editable column in gridview

Hi,

I created an ASP.NET 4 columns gridview programmatically using VB.NET. The first two columns are bound to checkboxes and a database. When the user selects one or more checkboxes the database information populates the first two columns. I want the user to be able to enter data into the second two columns' rows. Is this possible and, if it is, how is it accomplished? Following is the code for the gridview:

Expand|Select|Wrap|Line Numbers
  1. Private Sub BindGridView()
  2.         'Dim da As New DataLayer.SqlDataAccess
  3.         'Dim sql As String = "Select * from categories"
  4.         Dim dt As New DataTable '= da.GetDataTable(sql)
  5.         dt.Columns.Add(New DataColumn("Branch"))
  6.         dt.Columns.Add(New DataColumn("Team"))
  7.         dt.Columns.Add(New DataColumn("Reg Hrs Allocated"))
  8.         dt.Columns.Add(New DataColumn("OT Hrs Allocated"))
  9.         dt.Columns(2).ReadOnly = False
  10.         dt.Columns(3).ReadOnly = False
  11.         Dim PlaceHolder As DataRow = dt.NewRow
  12.         dt.Rows.Add(PlaceHolder)
  13.  
  14.         Dim RS As SqlDataReader = ClsData.getRecordSet("Select Distinct ISNULL([Team], 'N/A') As Team, [Branch_Initials] As Branch From dbo.Employees Order By Branch_Initials", ClsData.ConnectionString)
  15.         If RS.HasRows Then
  16.             While RS.Read
  17.                 System.Diagnostics.Debug.Print(RS("Branch") & ("Team"))
  18.                 Dim rw As DataRow = dt.NewRow
  19.                 rw.Item("Branch") = RS("Branch")
  20.                 rw.Item("Team") = RS("Team")
  21.                 dt.Rows.Add(rw)
  22.             End While
  23.         End If
  24.         grdAsgnTm.DataSource = dt
  25.         grdAsgnTm.DataBind()
  26.         For i As Integer = 1 To grdAsgnTm.Rows.Count - 1
  27.             grdAsgnTm.Rows.Item(i).Visible = False
  28.         Next
  29.  
  30.     End Sub
Thanks - John
Nov 9 '09 #1
9 4770
Frinavale
9,735 Expert Mod 8TB
You can let the user edit information displayed in a GridView.
You have to provide an EditTemplateItem for each column that you want to let the user edit.

All the information you need on GridViews and any other .NET controls can be found in the MSDN Library. This resource should get you pointed in the right direction....there are multiple articles on GridViews there. I recommend bookmarking the MSDN Library and using it as your primary resource when developing in .NET.

-Frinny
Nov 9 '09 #2
Frinavale
9,735 Expert Mod 8TB
What have you tried so far to get the second 2 columns to be editable?

Have you tried using a TemplateField.ItemTemplate to display TextBoxes for the content displayed in the GridView?
Nov 9 '09 #3
Thanks again. Read the info from your link - not really understood. This is what I did - all of it:
Expand|Select|Wrap|Line Numbers
  1. Imports System.Data.SqlClient
  2. Imports System.Data
  3.  
  4. Partial Class TMS_Site_ProjectNewAsgnTeam
  5.     Inherits System.Web.UI.Page
  6.  
  7.     Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles form2.Load
  8.         txtBrProj.Text = Session("ddlRasText")
  9.         txtBrTmRegHrs.Text = Session("txtProjRegHrsAl")
  10.         txtBrTmOTHrs.Text = Session("txtProjOTHrsAl")
  11.         txtBrTmStartDate.Text = Session("StrtDte")
  12.         txtBrTmEndDate.Text = Session("EndDte")
  13.         BindGridView()
  14.  
  15.     End Sub
  16.  
  17.     Private Sub BindGridView()
  18.         'Dim da As New DataLayer.SqlDataAccess
  19.         'Dim sql As String = "Select * from categories"
  20.         Dim dt As New DataTable '= da.GetDataTable(sql)
  21.         dt.Columns.Add(New DataColumn("Branch"))
  22.         dt.Columns.Add(New DataColumn("Team"))
  23.         dt.Columns.Add(New DataColumn("Reg Hrs Allocated"))
  24.         dt.Columns.Add(New DataColumn("OT Hrs Allocated"))
  25.         dt.Columns(2).ReadOnly = False
  26.         dt.Columns(3).ReadOnly = False
  27.         Dim PlaceHolder As DataRow = dt.NewRow
  28.         dt.Rows.Add(PlaceHolder)
  29.  
  30.         Dim RS As SqlDataReader = ClsData.getRecordSet("Select Distinct ISNULL([Team], 'N/A') As Team, [Branch_Initials] As Branch From dbo.Employees Order By Branch_Initials", ClsData.ConnectionString)
  31.         If RS.HasRows Then
  32.             While RS.Read
  33.                 System.Diagnostics.Debug.Print(RS("Branch") & ("Team"))
  34.                 Dim rw As DataRow = dt.NewRow
  35.                 rw.Item("Branch") = RS("Branch")
  36.                 rw.Item("Team") = RS("Team")
  37.                 dt.Rows.Add(rw)
  38.             End While
  39.         End If
  40.         grdAsgnTm.DataSource = dt
  41.         grdAsgnTm.DataBind()
  42.         For i As Integer = 1 To grdAsgnTm.Rows.Count - 1
  43.             grdAsgnTm.Rows.Item(i).Visible = False
  44.         Next
  45.  
  46.     End Sub
  47.  
  48.     Protected Sub btnSubmitAsgnTeam_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnSubmitAsgnTeam.Click
  49.         Session("txtBrProj") = txtBrProj.Text
  50.         Session("txtBrTmRegHrs") = txtBrTmRegHrs.Text
  51.         Session("txtBrTmOTHrs") = txtBrTmOTHrs.Text
  52.         Session("txtBrTmStartDate") = txtBrTmStartDate.Text
  53.         Session("txtBrTmEndDate") = txtBrTmEndDate.Text
  54.         Response.Redirect("ProjectNewAsgnMmbr.aspx")
  55.     End Sub
  56.  
  57.     Protected Sub Branch_CheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles chkDVTT.CheckedChanged, chkLM.CheckedChanged, chkVEB.CheckedChanged, chkVMB.CheckedChanged, chkVUB.CheckedChanged
  58.         Dim TempValues As String = ""
  59.         If chkDVTT.Checked = True Then
  60.             TempValues += "'DVTT', "
  61.             txtDVTTRegHrs.Enabled = True
  62.             txtBrDVTTOTHrs.Enabled = True
  63.         Else
  64.             txtDVTTRegHrs.Enabled = False
  65.             txtBrDVTTOTHrs.Enabled = False
  66.         End If
  67.  
  68.         If chkLM.Checked = True Then
  69.             TempValues += "'LM', "
  70.             txtBRLMRegHrs.Enabled = True
  71.             txtBrLMOTHrs.Enabled = True
  72.         Else
  73.             txtBRLMRegHrs.Enabled = False
  74.             txtBrLMOTHrs.Enabled = False
  75.         End If
  76.  
  77.         If chkVEB.Checked = True Then
  78.             TempValues += "'VEB', "
  79.             txtBrVEBRegHrs.Enabled = True
  80.             txtBrVEBOTHrs.Enabled = True
  81.         Else
  82.             txtBrVEBRegHrs.Enabled = False
  83.             txtBrVEBOTHrs.Enabled = False
  84.         End If
  85.  
  86.         If chkVMB.Checked = True Then
  87.             TempValues += "'VMB', "
  88.             txtBrVMBRegHrs.Enabled = True
  89.             txtBrVMBOTHrs.Enabled = True
  90.         Else
  91.             txtBrVMBRegHrs.Enabled = False
  92.             txtBrVMBOTHrs.Enabled = False
  93.         End If
  94.  
  95.         If chkVUB.Checked = True Then
  96.             TempValues += "'VUB', "
  97.             txtBrVUBRegHrs.Enabled = True
  98.             txtBrVUBOTHrs.Enabled = True
  99.         Else
  100.             txtBrVUBRegHrs.Enabled = False
  101.             txtBrVUBOTHrs.Enabled = False
  102.         End If
  103.  
  104.         If TempValues <> "" Then
  105.             TempValues = TempValues.Substring(0, TempValues.Length - 2)
  106.             grdAsgnTm.Rows.Item(0).Visible = False
  107.         Else
  108.             grdAsgnTm.Rows.Item(0).Visible = True
  109.         End If
  110.  
  111.  
  112.         For i As Integer = 1 To grdAsgnTm.Rows.Count - 1
  113.             If TempValues.Contains(grdAsgnTm.Rows.Item(i).Cells(0).Text) Then
  114.                 grdAsgnTm.Rows.Item(i).Visible = True
  115.             Else
  116.                 grdAsgnTm.Rows.Item(i).Visible = False
  117.             End If
  118.  
  119.         Next
  120.     End Sub
  121. End Class
Nov 9 '09 #4
Frinavale
9,735 Expert Mod 8TB
I should caution you that if you bind data to your GridView in the PageLoad event you will lose the data entered by the user. I would put that in the Page PreRender event if I were you to avoid this problem....but that's not the problem (yet).

In your ASP code you have a GridView that probably looks something like the following:
Expand|Select|Wrap|Line Numbers
  1. <asp:GridView ID="grdAsgnTm" runat="server"  AllowPaging="true" AutoGenerateColumns="true" AllowSorting="true">
  2.  
  3. </asp:GridView>
You can supply "templates" to tell the GridView how to display the data.
You use the TemplateField to do this.

For each column create a TemplateField and tell it how the data should be displayed when the user is viewing the data or editing the data.

For example:
Expand|Select|Wrap|Line Numbers
  1. <asp:GridView ID="grdAsgnTm" runat="server"  AllowPaging="true" AutoGenerateColumns="true" AllowSorting="true">
  2.   <Columns>
  3.     <asp:TemplateField HeaderText="Branch">
  4.       <ItemTemplate>
  5.         <%#Eval("Branch")%>
  6.       </ItemTemplate>
  7.       <EditItemTemplate>
  8.       </EditItemTemplate>
  9.     </asp:TemplateField>
  10.  
  11.     <asp:TemplateField HeaderText="Team">
  12.       <ItemTemplate>
  13.         <%#Eval("Team")%>
  14.       </ItemTemplate>
  15.       <EditItemTemplate>
  16.       </EditItemTemplate>
  17.     </asp:TemplateField>
  18.  
  19.    <asp:TemplateField HeaderText="Reg Hrs Allocated">
  20.       <ItemTemplate>
  21.         <asp:TextBox ID="TxtRegHrsAllocated" runat="server" Text='<%#Bind("Reg Hrs Allocated")%>'></asp:TextBox>
  22.       </ItemTemplate>
  23.       <EditItemTemplate>
  24.       </EditItemTemplate>
  25.     </asp:TemplateField>
  26.  
  27. <asp:TemplateField HeaderText="OT Hrs Allocated">
  28.       <ItemTemplate>
  29.         <asp:TextBox ID="TxOTHrsAllocated" runat="server" Text='<%#Bind("OT Hrs Allocated")%>'></asp:TextBox>
  30.       </ItemTemplate>
  31.       <EditItemTemplate>
  32.       </EditItemTemplate>
  33.     </asp:TemplateField>
  34.  
  35.   </Columns>
  36. </asp:GridView>
Notice how I have set the GridView's AutoGenerateColumns to False. Now the columns are not automatically created for me. Instead, the GridView will use the columns that I have specified in the <Columns></Columns> section.

I have specified that 4 columns. These columns are TemplateFields. Within each column/TemplateField I have told the GridView what controls to use to display the data that the GridView is being bound to.

The first 2 columns will just display text.
The next to columns will display the data in TextBoxes.

Does this make sense so far?

-Frinny
Nov 9 '09 #5
Thank you very much.

What you stated makes sense and I shall try it tomorrow.

John
Nov 9 '09 #6
I managed to get the gridview working the way I want by coding the following:
For the BindGridView() subroutine I added text boxes to the respective columns using the appropriate index number identifiers. I then captured the user entries so that I could carry the data to the next session (web page in this instance) and propagate the information.
I prefer to do as little as possible with ASP.NET and provide the site's functionality via VB.NET. That is why I did not more completely define the gridview in ASP.

Thank you for your help.

Expand|Select|Wrap|Line Numbers
  1.  Private Sub BindGridView()
  2.         'Dim da As New DataLayer.SqlDataAccess
  3.         'Dim sql As String = "Select * from categories"
  4.         Dim dt As New DataTable '= da.GetDataTable(sql)
  5.         dt.Columns.Add(New DataColumn("Branch"))
  6.         dt.Columns.Add(New DataColumn("Team"))
  7.         dt.Columns.Add(New DataColumn("Reg Hrs Allocated"))
  8.         dt.Columns.Add(New DataColumn("OT Hrs Allocated"))
  9.         Dim PlaceHolder As DataRow = dt.NewRow
  10.         dt.Rows.Add(PlaceHolder)
  11.  
  12.         Dim RS As SqlDataReader = ClsData.getRecordSet("Select Distinct ISNULL([Team], 'N/A') As Team, [Branch_Initials] As Branch From dbo.Employees Order By Branch_Initials", ClsData.ConnectionString)
  13.         If RS.HasRows Then
  14.             While RS.Read
  15.                 System.Diagnostics.Debug.Print(RS("Branch") & ("Team"))
  16.                 Dim rw As DataRow = dt.NewRow
  17.                 rw.Item("Branch") = RS("Branch")
  18.                 rw.Item("Team") = RS("Team")
  19.                 dt.Rows.Add(rw)
  20.             End While
  21.         End If
  22.         grdAsgnTm.DataSource = dt
  23.         grdAsgnTm.DataBind()
  24.         For i As Integer = 1 To grdAsgnTm.Rows.Count - 1
  25.             grdAsgnTm.Rows.Item(i).Visible = False
  26.             grdAsgnTm.Rows.Item(i).Cells(2).Controls.Add(New TextBox)
  27.             grdAsgnTm.Rows.Item(i).Cells(3).Controls.Add(New TextBox)
  28.             DirectCast(grdAsgnTm.Rows.Item(i).Cells(2).Controls(0), TextBox).Text = 0
  29.             DirectCast(grdAsgnTm.Rows.Item(i).Cells(3).Controls(0), TextBox).Text = 0
  30.         Next
  31.  
  32.     End Sub
  33.  
  34.     Protected Sub btnSubmitAsgnTeam_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnSubmitAsgnTeam.Click
  35.         Session("txtBrProj") = txtBrProj.Text
  36.         Session("txtBrTmRegHrs") = txtBrTmRegHrs.Text
  37.         Session("txtBrTmOTHrs") = txtBrTmOTHrs.Text
  38.  
  39.         Dim BranchData As String = ""
  40.         If chkDVTT.Checked = True Then
  41.             BranchData += "DVTT,"
  42.             BranchData += txtDVTTRegHrs.Text & ","
  43.             BranchData += txtBrDVTTOTHrs.Text & "|"
  44.  
  45.         End If
  46.  
  47.         If chkLM.Checked = True Then
  48.             BranchData += "LM,"
  49.             BranchData += txtBRLMRegHrs.Text & ","
  50.             BranchData += txtBrLMOTHrs.Text & "|"
  51.  
  52.         End If
  53.  
  54.         If chkVEB.Checked = True Then
  55.             BranchData += "VEB,"
  56.             BranchData += txtBrVEBRegHrs.Text & ","
  57.             BranchData += txtBrVEBOTHrs.Text & "|"
  58.  
  59.         End If
  60.  
  61.         If chkVMB.Checked = True Then
  62.             BranchData += "VMB,"
  63.             BranchData += txtBrVEBRegHrs.Text & ","
  64.             BranchData += txtBrVEBOTHrs.Text & "|"
  65.         End If
  66.  
  67.         If chkVUB.Checked = True Then
  68.             BranchData += "VUB,"
  69.             BranchData += txtBrVUBRegHrs.Text & ","
  70.             BranchData += txtBrVUBOTHrs.Text & "|"
  71.         End If
  72.  
  73.         Session("BranchData") = BranchData
  74.         Dim grdTmData As String = ""
  75.         For i As Integer = 2 To grdAsgnTm.Rows.Count - 1
  76.             If grdAsgnTm.Rows.Item(i).Visible = False Then
  77.                 If Val(DirectCast(grdAsgnTm.Rows.Item(i).Cells(2).Controls(0), TextBox).Text) > 0 Or Val(DirectCast(grdAsgnTm.Rows.Item(i).Cells(3).Controls(0), TextBox).Text) > 0 Then
  78.                     grdTmData += grdAsgnTm.Rows.Item(i).Cells(0).Text & ","
  79.                     grdTmData += grdAsgnTm.Rows.Item(i).Cells(1).Text & ","
  80.                     grdTmData += DirectCast(grdAsgnTm.Rows.Item(i).Cells(2).Controls(0), TextBox).Text & ","
  81.                     grdTmData += DirectCast(grdAsgnTm.Rows.Item(i).Cells(3).Controls(0), TextBox).Text & "|"
  82.                 End If
  83.             End If
  84.         Next
  85.         Session("grdAsgnTmData") = grdTmData
  86.         Response.Redirect("ProjectNewAsgnMmbr.aspx")
  87.     End Sub
Nov 10 '09 #7
Frinavale
9,735 Expert Mod 8TB
It is a lot more difficult to do this dynamically.
If you don't have to use dynamic controls then you should avoid doing so if you're new to this...

Of course, it is possible to dynamically create columns for your GridView. You should still use TemplteFields for this purpose for a bunch of reasons that I will address in a minute...but instead of declaratively defining them (in the ASPX page) you'll do so dynamically.

Every control that you dynamically create will have to be instantiated during the Page Init event.

The reason for this is because right after the Page Init event ViewState is loaded for all of the controls that the page uses. The ViewState contains state information for the control...

For example, if you have a TextBox on the page, the TextBox is instantiated in the Page Init event and right after this the TextBox's ViewState is loaded which contains the text that the user entered. Now you're able to access the TextBox.Text property to retrieve the text entered by the user.

The ViewState also contains event information. If your control was a button and the user clicked the button, the Click Event for the button is created when the ViewState for the button is loaded.

If the button was not instantiated during the Page Init event, then the Button Click Event would not be loaded and your code won't be executed.

I hope this makes my point.

So, in your case you will have to create the columns for the GridView in the Page Init event. That way the ViewState information for the columns can be loaded and you can get the text the user entered, and handle any events that the columns may have raised.


Now back to theTemplateField.

The reason why I am recommending that you use the TemplateField is because they exist so that you achieve what you want to achieve.

These controls are data-bound and let you customize how the data that they're bound to is displayed and interacted with. Another important aspect to these controls is that they use the INamingContainer interface. This interface makes sure that each dynamic control within the TemplateField (like your TextBoxes) have unique IDs etc. This lets you use the FindControl() method to retrieve the dynamic TextBoxes in the columns so that you can get the text that the user entered (right now, with your solution, you can't do this).....It takes a lot of work out of re-inventing the wheel.

So, if you Really want to dynamically add columns to your GridView I can help you through it but you should first familiarize yourself with how to use dynamic controls in ASP.NET, the INamingContainer Interface and also the ITemplate Interface because you need to have a very firm understanding of all of these topics before you start down this road.

I still think that you should avoid dynamically creating the columns for the GridView. From past experience I can tell you that it can quickly become very tricky to maintain this, even when you know what you're doing.

**edit**
After that whole huge post it occurred to me that you may not realize the Data that is displayed in the GridView can be dynamically created very easily....but the columns (the structure/layout) for the GridView are very hard to dynamically create.

Typically overall structure/layout of the GridView doesn't change. You know that you what columns you want to display, and what controls should be used to display the data in the columns. Therefore, there usually is no need to dynamically define the GridView's columns.

It is the data that is displayed in the GridView that is dynamic.

**close edit**


-Frinny
Nov 10 '09 #8
Frinny,

Impressive! Thank you very much for the information; for taking the time to reply; for taking the time to post such a concise and thorough explanation; and, for sharing your time, resources, and knowledge. Your actions are very much appreciated.

I am aware of the difficulties of programming dynamically. That approach is the preferred method in this particular shop. I am a neophyte with ASP.NET / VB.NET but, I am not new to programming. The dynamic approach will quickly be mastered and solely employed. Your information is very, very helpful.

Sincerely,

John
Nov 11 '09 #9
Frinavale
9,735 Expert Mod 8TB
It's too bad that your style is like this.

There is a great benefit to keeping the page design separate from the logic separate from the back end. (I am a huge fan of the Model - View - Controller concept).

But since you need to do this dynamically, let's get to it!

The first thing I suggest is to implement a class that you can use as your Template.

The class will implement the ITemplate interface (that I touched on briefly earlier) and will specify how the column look.

Check out the link for the ITemplate Interface because I think it has a good example on how to implement it. Should get you going in the right direction :)

-Frinny
Nov 11 '09 #10

Sign in to post your reply or Sign up for a free account.

Similar topics

4
by: Stephan Bour | last post by:
Hi, I have a datagrid databound to a SQL query. I'd like to allow editing of some columns but not all. Is there a way to turn off the conversion of the datagrid cells to textboxes for some columns...
3
by: Mike P | last post by:
Is it possible to make an editable gridview so that certain rows are editable and other are not editable, dependent upon a value in one of the rows columns? *** Sent via Developersdex...
0
by: Frank | last post by:
Hello All, I am working with VS.NET 2005 and I have an editable GridView whose HTML markup is shown below. In short, when the user clicks on the Edit button, one of the textboxes is replaced...
0
by: Frank | last post by:
Hello All, I am working with VS.NET 2005 and I have an editable GridView whose HTML markup is shown below. In short, when the user clicks on the Edit button, one of the textboxes is replaced...
1
by: Wannabe | last post by:
Is there a .Net way to create an editable gridview that has the date (showing two weeks in the future) as the header, and has about twenty rows? So basically the grid would be a 14 x 20 table that...
1
by: news-server.maine.rr.com | last post by:
Hi, I have the following bound to a database column and want the URL field to be editable in the GridView control. When the "Edit" link is clicked the field remains readOnly. ...
2
by: =?Utf-8?B?Sm9zaCBTY2htaWR0?= | last post by:
I have a gridview that is being used for managing inventory. The default view shows the stock currently available. When editing I don't want the stock to be directly edited, rather the user will...
4
by: mohaaron | last post by:
This seems like it should be simple to do but for some reason I have been unable to make it work. I would like to databind a SqlDataSource to a GridView during the click event of a button. This...
6
by: dipalichavan82 | last post by:
i want editable gridview in C# vs2005.i want a column get added to gridview with edit button. once i click on edit button at runtime,all cells shud become textbox and edit should be replaced by...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
0
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.