Xamarin Forms: MasterPage Helper class - c#

My current app has multiple master detail pages. I want to create a helper class which has a function that accepts list of PageModels-Pages( ViewModels-views ) which I can iterate through and create master detail pages.
MyCurrent Code:
public static Page SetupMasterDetailNav<T,U>( Dictionary<T,string> Menu)
where T : class
//In Dictionary T is ViewModel(PageModel) ,
String is name displayed on Master page
{
var masterDetail = new FreshMasterDetailNavigationContainer();
foreach (KeyValuePair<T,string> item in Menu)
{
masterDetail.AddPage<item.Key>(item.Value);
}
masterDetail.Init("");
return masterDetail;
}
This code doesn't work.It tells me item.key is a variable and cannot be used as a type Can any one suggest me a better approach or how else I can achieve my goal ?

The AddPage<T> method is a generic method, which expects a type. In this case it is FreshBasePageModel. The normal usage would be something like:
masterDetail.AddPage<MyViewModel>("MyPage", model);
or:
masterDetail.AddPage<MyViewModel>("MyPage");
Since your method is already generic, and seems you want it to be the type of the ViewModel you could simply do:
masterDetail.AddPage<T>(item.Value);
To do this you must change the your method signature to something like:
public static Page SetupMasterDetailNav<T,U>(Dictionary<T,string> Menu)
where T : FreshBasePageModel
Not sure what the U is used for in your case, you haven't shown usage of it.
Why are you even doing this is puzzling me.

Related

How to check if EPIserver.Core.ContentReference is true or contains something?

We have a block in our EPIserver website called KeyVisualBlock. This is basically the header section of our pages consisting of things like a hero image, page title.
Our users would like to be able to insert a form into this area of the page.
So I have modified our Model KeyVisualBlock.cs to include the ability to select a form by adding:
[CultureSpecific]
[Display(Order = 90,
GroupName = SystemTabNames.Content)]
[AllowedTypes(typeof(FormContainerBlock))]
public virtual ContentReference ContactForm { get; set; }
Now I would like to check if this field contains a form and then display the form in our view. So in our View I am trying to do something like this:
#{
if (Model.CurrentKeyVisualBlock.ContactForm) {
// do something.
}
}
But Visual Studio informs me that:
Cannot implicitly convert type 'EPIserver.Core.ContentReference' to
type 'bool'
What is the preferred way to check this?
You can check whether the content reference is set like this:
if (!ContentReference.IsNullOrEmpty(Model.CurrentKeyVisualBlock.ContactForm))
{
// Do stuff
}
But keep in mind that even though the content reference isn't null the content it refers to might not exist. To be really sure you need to actually load the content, preferably like this:
// Constructor injected IContentRespository into field contentRepository.
if (this.contentRepository.TryGet<FormContainerBlock>(Model.CurrentKeyVisualBlock.ContactForm, out var formContainerBlock))
{
}

How do I open a form in a method if passed its name as a parameter

I am trying to create a standard method to open a form based on the parameter passed to it. Basically, to get this done:
using (Quotes newQte = new Quotes())
{
newQte.ShowDialog();
}
by replacing:
Quotes with a passed parameter, e.g. FormToOpen.
Is this at all possible?
It is possible using a "Factory Method" to do so.
You would define FormToOpen like this (I'm renaming it to createForm() for clarity):
Func<Form> createForm;
So the code would look something like this:
private void MakeAndDisplayForm(Func<Form> createForm)
{
using (var form = createForm())
{
form.ShowDialog();
}
}
You would call it like this:
MakeAndDisplayForm(() => new MyForm());
Where MyForm is the type of form that you want MakeAndDisplayForm() to create.
It's fairly common to do this kind of thing; often you pass the creator function to the constructor of a class. Then that class uses the creator function later on to create things that it can use, without knowing how they were created.
This is a form of Depencency Injection.
(Disclaimer: All error checking elided for brevity)
Create a method that creates the form you want to display, based on a parameter:
public static Form CreateAppropriateForm(int formToOpen)
{
switch (formToOpen) {
case 0:
return new Quotes();
case 1:
return new Citations();
case 2:
return new References();
default:
throw new ArgumentException("Invalid parameter value.");
}
}
Where Quotes, Citations and References would be your form classes, derived from Form.
Then, you could invoke that method when you want to show your form:
using (Form form = CreateAppropriateForm(2)) {
form.ShowDialog();
}
Here shown with the example of value 2 - but you are free to insert any other expression that yields a value usable for your form selection method there.
Of course, you can also declare formToOpen in a more meaningful way, if that is suitable for your application. For example, you can declare it as a custom enum type, where each enum value denotes a particular form.

Editing a List<T> in between two windows forms (C#)

I have a query regarding maintaining a List in between two windows forms. It's for a project where I need to create an address book.
I have chosen to maintain the contact details in the form of a List. My first windows form (form1) contains a master copy of a list AddressBook, which contains the address book.
I hardcoded 4 entries into the address book list in order to experiment and get the simple functions such as 'add' and 'edit' working.
I have a second windows form called Add, in which I can add new entries to the list. This works fine. I can add a new contact in the ADD form and this shows up in the initial form1, master form.
My problem arises in the EDIT form. I pass the AddressBook (master) list to the EDIT form. The EDIT form takes the master list and I am able to manipulate the records in that list. However when it comes to sending back the new list to the master page (form1), it does not pick it up. I am using the same code as I do in the ADD form which successfully sends back the new list. However this code does not work when sending back an edited list.
Here is my AddressBook property within form1
public List<Contact> addressBook;
public List<Contact> AddressBook
{
get { return addressBook;}
set {addressBook = value;}
}
Within EDIT:
public Edit()
{
InitializeComponent();
temp = Master.AddressBook; // temp is the temporary List I update within EDIT
}
** I then have my algorithm which successfully lets me EDIT the list temp. the list temp now has the edited list**
then when I hit the save button, I use the following code;
Master.AddressBook = temp;
All I need is for the list temp to be sent back to form1.
the code Master.AddressBook = temp; WORKS for when I add values to the list through the ADD form.
ADD FORM:
public Add()
{
InitializeComponent();
temp = Master.AddressBook;
}
**** code to add a new record into the list temp. the new record is called newRecord**********
private void btnAddClose_Click(object sender, EventArgs e)
{
stor.AddressBook = temp; // when I hit close on the form, it updates the master list AddressBook
this.Close();
}
This is all probably very poorly worded but in essence the only bit where my code fails is when I want to change my master Addressbook within form1 by replacing it with the list temp, which is the edited list from my EDIT form.
I think it's something to do with my AddressBook property. But this doesn't explain why I can replace AddressBook with a list containing new records but I can't replace it with a list containing edited records.
One way to accomplish this would be to make the list in Master static.
Master:
public static List<Contact> AddressBook { get; set; }
Note: You do not need the backing variable, and if you do want to use it, best practices would suggest that it be private. If you do decide to use it, it will also need to be static.
In the Add form, you would then gather the data to create a new Contact object and temp should, in fact, be just a Contact object.
Add Form:
private Contact newRecord = null;
public Add()
{
InitializeComponent();
newRecord = new Contact();
}
/**** code to add the user-input to the new Contact object ****/
private void btnAddClose_Click(object sender, EventArgs e)
{
Master.AddressBook.Add(newRecord);
this.Close();
}
Hope this helps.
This is where the Singleton pattern comes in handy: Implementing Singleton in C#
You will notice Application Settings uses this same patttern to allow you to globally access it without having to pass it around.
When I use a Singleton I typically make the class name like (TypeName)Manager (ex: AddressBookManager).
So the class might be something like this:
public static class AddressBookManager
{
#region Singleton
static readonly AddressBookManager instance = new AddressBookManager();
private AddressBookManager(); // prevent creating instances of this
public static AddressBookManager Current { get { return instance; } }
#endregion
AddressBook master = new AddressBook(); // the master address book
public AddressBook Master
{
get { return master; } // get the master address book
set { master = value; } // set the master address book
}
}
Then in each form you would access it like so:
var addressBook = AddressBookManager.Current.Master;
addressBook.Add(newRecord);
The problem you are experiencing with the Edit functionality probably has something to do with the way you are using temporary lists. By using a static, global list and merely adding/editing items inside of it, you don't run that problem. Since your Contact items are a class (not struct), their changes will be reflected in the list automatically since they are reference types.
The great part about Singleton classes is the ability to access them from anywhere in the project. The only caveat is that you need to be extra cautious when working with multi-threaded applications and Singleton classes.

Passing a parameter to a programmatically created User Control

Let me just preface this with: I Googled high and low for this, and found many examples and solutions, and I still can't figure this out.
In a .aspx.cs code behind file, I have the following:
NewsArticleList listall = NewsArticleManager.GetListAll();
foreach (NewsArticle x in listall)
{
Control c1 = (NewsArticleContainer)LoadControl("~/UserControls/NewsArticleContainer.ascx");
((NewsArticleContainer)c1).PopulateWithNewsArticle(x);
mynewspanel.Controls.Add(c1);
}
I have a method in the User Control called PopulateWithNewsArticle() that accepts a NewsArticle, and populates the User Control's web controls accordingly:
public void PopulateWithNewsArticles(NewsArticle x)
{
lbltitle.Text = x.Title;
lblcategory.Text = x.Category;
//...etc.
}
Now this works, this is fine. But what I would like to learn/understand, is how I can pass the NewsArticle x to the User Control when I LoadControl(), so that upon creation of the User Control, I can unpackage the NewsArticle on the User Control's Page_Load, and set the web control properties from right when the User Control is instantiated as opposed to doing it after instantiation with the PopulateWithNewsArticle method (like I have it now).
Our you can expose public property NewsArticle in the NewsArticleContainer.ascx, so you will have initialization code like this:
var control = (NewsArticleContainer)LoadControl("~/UserControls/NewsArticleContainer.ascx");
control.NewsArticle = x;
You could use
Control c1 =
(NewsArticleContainer)LoadControl(typeof(NewsArticleContainer),new object[]{ x });
This one is an overloaded of Page.LoadControl(), It has this syntax
public Control LoadControl(
Type t,
Object[] parameters
)
After that you would have to create a valid constructor for your UserControl too, which could be something like this
class NewsArticleContainer:System.Web.UI.UserControl
{
public NewsArticleContainer(NewsArticle x)
{
// Some cool code stuff here
}
}
For more on this go here.

C# syntax to get access to webcontrol in different file (aspx)

Within my Website project, I have some aspx pages, javascript files, and a custom C# class I called MyCustomReport. I placed a Image box with an ID of Image1 inside SelectionReport.aspx. I need to get access to that Image1 inside MyCustomReport.cs so I can turn it on and off based on conditions. What code do I need to do this? Thanks everyone
You'll need to pass the instance of Image control to MyCustomReport. From there you'll be able to set it's Visible property to true or false.
Probably something like this
public partial class SelectionReport : Page
{
// your code here
protected void Page_Load( object sender, EventArgs e ){
MyCustomReport myCustomReport = new MyCustomReport();
myCustomReport.MyReport( Image1 );
}
}
public class MyCustomReport
{
public void MyReport( Image arg ){
// some more code
arg.Visible = false; // or true
}
}
EDIT derek is right, you won't need the entire page, just the image.
it sounds a bit odd to do it that way. You could pass the control to the class method using the ref keyword, then the class could modify it:
doSomething(data, MyUserControl);
I think a better implementation would be for your class to have a method or property that the page could query to turn the control on or off.

Categories