Adding Request Parameters to a DotNetNuke page - dotnetnuke

I'm wondering if there's a simple way to specify a request parameter (i.e. CategoryID) in the page header section or somehow associated to a particular page that would be picked up by Request("CategoryID")? Or another simple approach to easily specify a Request Parameter for a DotNetNuke page that would be picked up by Request(). We need different pages to have different categoryid's.
Detail
We've got a module that appears on every page. It always makes a call to Request("CategoryID") to see if a category is defined for the page, if so, it filters it's results list by that category. Normally this is used when the CategoryID is specified in the URL. But in this case, we want to specify it some other way. I could probably specify a skin object as part of the skin that would look at the URL and map to the appropriate categoryID and write it out as a session variable but I'm looking for a simpler approach.
Any ideas?

I ended up creating a SkinObject that handles this. Currently, I've hard coded the mapping from the TabID to the CategoryID and then I do a Response.Redirect to the page with the CategoryID appended to the URL.
I initially tried writing the CategoryID to the ViewState in the Skin Objects Page.Init but that wasn't getting picked up by the module.
I still think there is a better way (I'm worried about the SEO impact of this) but this is working for now until I come up with something better or add functionality to the module.
NameSpace DotNetNuke.UI.Skins.Controls
Partial Class MapURLToCategoryID
Inherits UI.Skins.SkinObjectBase
Protected Sub Page_Init(sender As Object, e As System.EventArgs) Handles Me.Init
If Request("CategoryID") <> "" Then
Exit Sub
End If
Dim id As Int16 = -1
Select Case Request("tabid")
Case 92
id = 14
Case 93
id = 15
Case 227
id = 38
Case 95
id = 19
Case 91
id = 13
Case 226
id = 17
Case 94
id = 16
Case Else
'do nothing
End Select
If id <> -1 Then
Response.Redirect(NavigateURL("", "CategoryID=" & id.ToString), False)
End If
End Sub
End Class
End Namespace

This allows you to store and retrieve CategoryID in the Page's keywords. This would be called upon page load.
Dim TC As New TabController
Dim TI As DotNetNuke.Entities.Tabs.TabInfo = TC.GetTab(TabId, PortalId, True)
Dim tokens() As String = TI.KeyWords.Split(","c)
For Each token As String In tokens
Dim tokens2() As String = Trim(token).Split(":"c)
If tokens2.Length = 2 AndAlso tokens2(0) = "CategoryID" Then
Response.Write("My CategoryID is " & tokens2(1))
End If
Next

Related

WF: Workflow Designer: List of InArgument added dynamically : How to get value during workflow execution

I have built a workflow designer that allows to enter a list of email addresses.Each email in the list needs to be an InArgument(Of String) so they can be individually edited/added using variables.
On my Activity, I have a property that is declared like so:
Public Property [To] As ObservableCollection(Of InArgument(Of String))
My designer is wired up and populating this collection properly.
However during the execution, I do not know how to get the run-time value for each InArgument that was added.
When we are executing the workflow and iterating for each InArgument added to the list, I attempted to get the value as shown below but that fails:
For Each toAddress As InArgument(Of String) In Me.To.ToList()
Dim emailToAddress As String = toAddress.Get(_Context)
Next
The error we get is “The argument of type '<type>' cannot be used. Make sure that it is declared on an activity” and type is a string in my case...
The error we get sort of make sense because we haven’t declared a property on the activity since it was added dynamically to the list and therefore cannot get the value using the syntax shown below:
The_Property_Name.Get(_Context)
Can someone help? I can't seem to find anything. Should I be doing a different approach?
I figured it out so I will answer my own question! All we need to do is explicitly add the collection items to the metadata by overriding CacheMetadata() method on the activity. This then makes it available to the workflow context.
First we add them to the context:
Protected Overrides Sub CacheMetadata(ByVal metadata As CodeActivityMetadata)
MyBase.CacheMetadata(metadata)
Dim i As Integer = 0
For Each item As InArgument(Of String) In Me.To
Dim runTimeArg As RuntimeArgument = New RuntimeArgument("TO" & i.ToString(), item.ArgumentType, item.Direction, False)
metadata.Bind(item, runTimeArg)
metadata.AddArgument(runTimeArg)
i = i + 1
Next
End Sub
Then when executing, we get the values like this
For Each item As InArgument(Of String) In Me.To
Dim email As String = _Context.GetValue(item)
Next

Entity Framework Child & Parent (List Property)

I'm working on a project with EF5, Vb.net, AJAX (Javascript), ASMX-Webservices and HTML.
My question is if i have (example classes):
Public Class Company
Public Property CompanyId As Integer
Public Property Name As String
Public Overridable Property Companytype As Companytype
End Class
and the Class:
Public Class Companytype
Public Property CompanytypeId As Integer
Public Property Name As String
-> Public Overridable Property Companies As List(Of Company)
End Class
do I need the -> marked line?
I'm afraid but I really don't know which advance this line brings to me.
Actually I can read all the Companies of a Companytype like this:
Public Shared Function PostCompanyTypeCompanies() As List(Of Company)
Dim db As New Context
Dim x As Integer = 1
Dim y = (From c In db.Companies Where c.CompanyType.CompanyTypeId = x Select New With _
{c.Name, _
c.CompanyType})
Dim z As List(Of Company) = y.AsEnumerable() _
.Select(Function(t) New Company With _
{.Name = t.Name, _
.CompanyType = t.CompanyType}).ToList()
Return z
End Function
This with 'x' is just an example, I can just pass the CompanytypeId to the function.
The problem with the lists is, I always get a circular reference when I want to get the Companytypes for a new Company and I can't access the companytype of a Company like:
Company.Companytype.Name
When I do it without the list everything works fine, because i can store the whole Companytpe to the Company.
I tried the other possibility with setting the Getter of the Child & Parent Properties to Protected then the problem was logically also that I couldn't access the variable as I described a 3 lines above.
So the important question is: Is this -> List Property mandatory?
Thanks for you help.
do I need the -> marked line? NO. It is redundant information (with no real use), which potentially, might provoke consistency errors. Example:
Dim company1 As New Company()
Dim listCompanies As New List(Of Company)()
Dim companiesType1 As New Companytype()
listCompanies.Add(company1)
With companiesType1
.CompanytypeId = 1
.Name = "Type 1"
.Companies = listCompanies
End With
With company1
.CompanyId = 1
.Name = "1"
.Companytype = companiesType1
End With
The code above defines Company1 and the associated type (companiesType1... although we have the problem of "first the egg or the chicken", what gives a first idea of why the chosen approach is erroneous). If you create a new company of the same type:
Dim company2 As New Company()
With company2
.CompanyId = 2
.Name = "2"
.Companytype = companiesType1
End With
You would have to redefine companiesType1 (update its Companies property), to keep the consistency. But, as far as this is redundant information, Companytype would "do the job" independently upon this fact:
If (company2.Companytype Is company1.Companytype) Then
'Both companies have the same type
End If
The aforementioned condition will always be true: either if companiesType1 contains the right information (was updated with company2) or not.
If you need to have a list of all the companies belonging to certain type, you should better rely on a different class storing all the values (e.g., allTheCompanies).

How to have a global Dictionary in VB.NET/WPF application to save data from different windows?

I am new to VB.NET and WPF.
I am building a "Questionnaire" app. Users will be presented sequentially with different questions/tasks (windows). After they respond on each question/task and press a "submit" button a new window will open with a new question/task, and previous window will close. After each question, when the button is pressed, I need to store data to some global object. After all questions are answered the data of this object should be written out to the output file.
I figured out that Dictionary will be the best to store the results after each window.
I am not sure how, where to create this global Dictionary and how to access it. Should I use View Model? If yes, can you give an example? Or, should it be just a simple class with shared property? (something like this)
EDIT 2: I tried many different ways recommended online
GlobalModule:
Module GlobalModule
Public Foo As String
End Module
GlobalVariables:
Public Class GlobalVariables
Public Shared UserName As String = "Tim Johnson"
Public Shared UserAge As Integer = 39
End Class
Global properties:
Public Class Globals
Public Shared Property One As String
Get
Return TryCast(Application.Current.Properties("One"), String)
End Get
Set(ByVal value As String)
Application.Current.Properties("One") = value
End Set
End Property
Public Shared Property Two As Integer
Get
Return Convert.ToInt32(Application.Current.Properties("Two"))
End Get
Set(ByVal value As Integer)
Application.Current.Properties("Two") = value
End Set
End Property
End Class
Here is where I save the data to global variables/properties in the first window. I need to store data in this subroutine before closing an old window and opening a new window. I use MessageBox just for testing.
Private Sub btnEnter_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnEnter.Click
Dim instructionWindow As InstructionsWindow
instructionWindow = New InstructionsWindow()
Application.Current.Properties("number") = textBoxValue.Text
Globals.One = "2"
Globals.Two = 3
MessageBox.Show("GlobalVariables: UserName=" & GlobalVariables.UserName & " UserAge=" & GlobalVariables.UserAge)
GlobalVariables.UserName = "Viktor"
GlobalVariables.UserAge = 34
GlobalModule.Foo = "Test Foo"
'testing if it saved tha value
'MessageBox.Show(Application.Current.Properties("number"))
Application.Current.MainWindow.Close()
instructionWindow.ShowDialog()
End Sub
Next subroutine is where I am trying to retrieve the value from global Properties/variables in the second window, but message boxes come out empty. There might also the case that I am assigning values in a wrong way, or not reading them in a right way (casting?) :
Private Sub FlowDocReader_Initialized(ByVal sender As Object, ByVal e As System.EventArgs) Handles FlowDocReader.Initialized
' Get a reference to the Application base class instance.
Dim currentApplication As Application = Application.Current
MessageBox.Show(currentApplication.Properties("number"))
MessageBox.Show("One = " & Globals.One & " Two = " & Globals.Two)
MessageBox.Show("GlobalVariables: UserName=" & GlobalVariables.UserName & " UserAge=" & GlobalVariables.UserAge)
MessageBox.Show("GlobalModule.Foo = " & GlobalModule.Foo)
Dim filename As String = My.Computer.FileSystem.CurrentDirectory & "\instructions.txt"
Dim paragraph As Paragraph = New Paragraph()
paragraph.Inlines.Add(System.IO.File.ReadAllText(filename))
Dim document As FlowDocument = New FlowDocument(paragraph)
FlowDocReader.Document = document
End Sub
Thanks.
You can make public Dictionary property for form and put your dictionry to this property or make constructor with Dictionary argument.
You already have this dictionary Application.Properties
Look here, please.
First, you can define a dictionary (list of lists) as follows at the beginning of a form or in a module
Dim dic As New Dictionary(Of String, List(Of String))
As the user completes questions on a form, write the partucular form number and query results to a single record in the dic before going to the next form (place this code into the "Next" button):
'Assume q1response=3, q2response=4,..., qpresponse="text", etc.
Dim myValues As New List(Of String)
myValues.Add(formname)
myValues.Add(q1response)
myValues.Add(q2response)
.
.
myValues.Add(qpresponse)
dic.Add(username, myValues)
When a user is done, there will be multiple records in the dictionary, each of which starts with their name and is followed by question responses. You can loop through multiple dictionary records, where each record is for a user using the following:
For Each DictionaryEntry In dic 'this loops through dic entries
Dim str As List(Of String) = DictionaryEntry.Value
'here you can do whatever you want with results while you read through dic records
'username will be = str(0)
'formname will be str(1)
'q1 response on "formname" will be str(2)
'q2 response on "formname" will be str(3)
'q3 response on "formname" will be str(4)
...
Next
The trick is that there will be multiple dictionary records with results for one user, where record one can have results like "John Doe,page1,q1,q2,q3" and record 2 will be "John Doe,page2,q4,q5,q6." Specifically, the "str" in the above loop will be an array of string data containing all the items within each dictionary record, that is, in str(0), str(1), str(2),... This is the information you need to work with or move, save, analyze, etc.
You can always put all the code I provided in a class (which will be independent of any form) and dimension the sic is a Sub New in this class, with the updating .Add values lines in their own sub in this same class). Then just Dim Updater As New MyNewClassName. Call the Updater in each continue button using Call Updater.SubNameWithAddValues(q1,q2,...qp). It won't matter where you are in your program since you using a specific class. The one thing I noticed with my code is that you can only use the line that adds the "key" or the username once, so use it after the last query -so put it in a Sub Finished in your new class and call as Call Updater.Finished(username,q30,q31,last)

ISBN -> bookdata Lookup to fill in a database

Ok, I wanting to database a small library.
I've only had limited experience with databases, and none with querying from a webserver.
I'm going to want to retrieve information like title, Publisher, maybe author, description
the simplest way I can think of dooing this is looking them up via the ISBN.
I've come across isbndb.com before, but the API for accessing it seems rather complex.
I'm wondering how I should go about doing this.
This is an incomplete answer, but it should get you started (I've not worked with XML data as return).
This code has the basics:
Dim oHttp As Object
Set oHttp = CreateObject("Microsoft.XMLHTTP")
oHttp.Open "GET", "https://isbndb.com/api/books.xml?access_key=YourKey&results=texts&index1=isbn&value1=YourISBN", False
oHttp.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
oHttp.Send vbNullString
Debug.Print oHttp.responseText
The response from the web page is in the .responseText property of the XMLHTTP object. How you process that is beyond me. I know that one of the Access newsgroup gurus has published a tutorial on consuming web services from Access, but I can't locate it. This article might have something to do with the issue:
http://support.microsoft.com/kb/285329/en-us
You can use the MARC21 XML from the Library of Congress.
I did the same thing as you, building a database to house my library. Scanning in the ISBN collects the data from this URL
http://z3950.loc.gov:7090/voyager?version=1.1&operation=searchRetrieve&query=YOUR_ISBN&maximumRecords=1
The response data then fills in a form with all the data. You don't need an account, just that URL.
The response comes in XML (as mentioned), and you can parse from there using whatever language you want (my choice happens to be PHP).
The ISBNdb.com API looks simple. The following request should retrieve the information you want ... just substitute your access key for "YourKey" and the ISBN for "YourISBN".
https://isbndb.com/api/books.xml?access_key=YourKey&results=texts&index1=isbn&value1=YourISBN
The response is XML which contains information about the single book whose ISBN you submitted.
I recently had to do exactly this as we indexed our library for insurance purposes. Below is the code of the vba class I hacked together:
Option Compare Database
dim BookTitle As String
dim BookTitleLong As String
dim BookAuthorsText As String
dim BookPublisherText As String
dim BookSummary As String
dim BookNotes As String
dim accessKey As String
Private Sub Class_Initialize()
'Your isbnDB access key'
accessKey = "PUT ACCESSKEY HERE"
End Sub
Property Get Title() As String
Title = BookTitle
End Property
Property Get TitleLong() As String
TitleLong = BookTitleLong
End Property
Property Get AuthorsText() As String
AuthorsText = BookAuthorsText
End Property
Property Get PublisherText() As String
PublisherText = BookPublisherText
End Property
Property Get Summary() As String
Summary = BookSummary
End Property
Property Get Notes() As String
Notes = BookNotes
End Property
Public Function Lookup(isbn As String) As Boolean
Lookup = False
Dim xmlhttp
Set xmlhttp = CreateObject("MSXML2.xmlhttp")
xmlhttp.Open "GET", "https://isbndb.com/api/books.xml?access_key=" & accessKey & "&results=texts&index1=isbn&value1=" & isbn, False
xmlhttp.send
'Debug.Print "Response: " & xmlhttp.responseXML.XML'
Dim xmldoc
Set xmldoc = CreateObject("Microsoft.XMLDOM")
xmldoc.async = False
'Note: the ResponseXml property parses the server's response, responsetext doesn't
xmldoc.loadXML (xmlhttp.responseXML.XML)
If (xmldoc.selectSingleNode("//BookList").getAttribute("total_results") = 0) Then
MsgBox "Invalid ISBN or not in database"
Exit Function
End If
If (xmldoc.selectSingleNode("//BookList").getAttribute("total_results") > 1) Then
MsgBox "Caution, got more than one result!"
Exit Function
End If
BookTitle = xmldoc.selectSingleNode("//BookData/Title").Text
BookTitleLong = xmldoc.selectSingleNode("//BookData/TitleLong").Text
BookAuthorsText = xmldoc.selectSingleNode("//BookData/AuthorsText").Text
BookPublisherText = xmldoc.selectSingleNode("//BookData/PublisherText").Text
BookNotes = xmldoc.selectSingleNode("//BookData/Notes").Text
BookSummary = xmldoc.selectSingleNode("//BookData/Summary").Text
Lookup = True
End Function
Get an API key, paste the above code (with your key) into a new class module in the VBA editor (Insert->Class Module) and name the module "isbn". You also need to add a reference to "Microsoft XML" in the VBA editor (Tools->References)
You can test it works with the code snippet below in a normal vba module:
Public Function testlookup()
Dim book
Set book = New isbn
book.Lookup ("0007102968")
Debug.Print book.Title
Debug.Print book.PublisherText
End Function
Then just type "testlookup" into the immediate window (View->Immediate Window). You should see a response of:
The Times book of quotations
[Glasgow] : Times Books : 2000.
isbnDB can return more than the data I collect in the above class, read the API reference here: http://isbndb.com/docs/api/ and tailor the class to your needs.
I found this article very helpful in explaining how to use xmlhttp from within access:
http://www.15seconds.com/issue/991125.htm
The msdn pages on XML DOM Methods and XMLHttpRequest Object were also useful (because I'm a new user I can only post two active links, you'll have to replace the dots in the urls below):
msdn microsoft com/en-us/library/ms757828(v=VS.85).aspx
msdn microsoft com/en-us/library/ms535874(v=vs.85).aspx
What language are you using? You need a program/script to present a form where you can enter the ISBN, which would then get the data from isbndb.com and populate the database. I've used the API a bit, but not for some time, and it's pretty straightforward.

Infragistics UltraWinGrid EmptyDataText Equivalent?

We're using Infragistics UltraWinGrid as a base class for customized controls. One of the projects that will use this control to display search results has a requirement to display a user friendly message when no matches are located.
We'd like to encapsulate that functionality into the derived control - so no customization beyond setting the message to display is required by the programmer who uses the control. This would have to be done in generic fashion - one size fits all datasets.
Is there allowance in the UltraWinGrid for this type of usage already? If so, where would I find it hidden. :-)
If this functionality needs to be coded, I can think of an algorithm which would add a blank record to whatever recordset was set and place that into the grid. In your opinion, is this the best way to handle the solution?
I don't know if this will help, but here's to finishing up the thread. I didn't find a built in way, so I solved this problem as follows: In my class which inherits UltraGrid
Public Class MyGridPlain
Inherits Infragistics.Win.UltraWinGrid.UltraGrid
I added two properties, one to specify what the developer wants to say in the empty data case, and another to enable the developer to place their message where they want it
Private mEmptyDataText As String = String.Empty
Private mEmptyDataTextLocation As Point = New Point(30, 30)Public Shadows Property EmptyDataTextLocation() As Point
Get
Return mEmptyDataTextLocation
End Get
Set(ByVal value As Point)
mEmptyDataTextLocation = value
setEmptyMessageIfRequired()
End Set
End Property
Public Shadows Property EmptyDataText() As String
Get
Return mEmptyDataText
End Get
Set(ByVal value As String)
mEmptyDataText = value
setEmptyMessageIfRequired()
End Set
End Property
I added a method which will check for empty data and set the message if so. And another method which will remove the existing empty message.
Private Sub setEmptyMessageIfRequired()
removeExistingEmptyData()
'if there are no rows, and if there is an EmptyDataText message, display it now.
If EmptyDataText.Length > 0 AndAlso Rows.Count = 0 Then
Dim lbl As Label = New Label(EmptyDataText)
lbl.Name = "EmptyDataLabel"
lbl.Size = New Size(Width, 25)
lbl.Location = EmptyDataTextLocation
ControlUIElement.Control.Controls.Add(lbl)
End If
End SubPrivate Sub removeExistingEmptyData()
'any previous empty data messages?
Dim lblempty() As Control = Controls.Find("EmptyDataLabel", True)
If lblempty.Length > 0 Then
Controls.Remove(lblempty(0))
End If
End Sub
Last - I added a check for empty data to the grid's InitializeLayout event.
Private Sub grid_InitializeLayout(ByVal sender As Object, _
ByVal e As Infragistics.Win.UltraWinGrid.InitializeLayoutEventArgs) _
Handles MyBase.InitializeLayout
setEmptyMessageIfRequired()
End Sub

Resources