I'm building an ASPX web page where some links will be visible or invisible depending on the user's access level. My thought was rather than create multiple functions and turn each link on or off, I could keep things neat and tidy by making List<LinkButton> members, like:
private List<LinkButton> adminButtons = new List<LinkButton>();
private List<LinkButton> guestButtons = new List<LinkButton>();
private List<LinkButton> userButtons = new List<LinkButton>();
Then I'd call one function to make them all visible or invisible.
private void DisplayButtons(List<LinkButton> linkButtons, bool displayButtons) {
for (int i = 0; i < linkButtons.Count; i++) {
linkButtons[i].Visible = displayButtons;
}
}
But I hit two snags. Firstly, I couldn't figure out how to initialize the lists with the links. For example, I've got asp:LinkButtons with IDs like ID='Link_UserManagement', ID='Link_InventoryManagement', et cetera. I can do this in the ASPX.CS file, and it works:
Link_UserManagement.Visible = false;
Link_InventoryManagement.Visble = true;
But this doesn't work:
private List<LinkButton> adminButtons = new List<LinkButton>() { Link_UserManagement }
And then if I try adding them this way, then the List count increases, but the values are null:
adminButtons.Add(Link_UserManagement);
So obviously I don't understand something about how these links work. My question is, why isn't this working the way I thought it would?
Secondly, if there's a better way to go about hiding and showing content based on a user's access level, I'm open to suggestions.
I am trying to bind data from several datagrids and I don't want to view all of them every time I start app.
Is there any possibility to set it in settings? Or automaticaly set all datagrids as viewed?
Thanks
Maybe your thinking about this the wrong way? If you want your data before the table is shown what you need to do is get and store the data in a DataTable and then use that to play with. Then when it comes to displaying your DataGridView just simply bind the DataTable to it and display it. I have included a sample below. But if its just a case of showing the tables then either tablename.visable = false should do the trick or alternitivly if you have other elements such as a panel you could use panelname.BringToFront or tablename.SendToBack.
Lets begin the OOP example..
This you could have in another interface class where you want to manipulate the data. In this example this class would be IOptions, here you could have all the data tables you need for Options for example. You could have different Interface Classes representing certain parts of your program, but we will stick with options for now..
public DataTable mProgramOptionsList;
Then when the program starts (your main page / main.cs) you attach IOptions to any of the classes that need at this DataTable.
mIOptions = new IOptions();
mPresenterOptions = new PresenterOptions();
mPresenterOptions.AttachInterface(mIOptions);
mModelOptions = new ModelOptions();
mModelOptions.AttachInterface(mIOptions);
Example code in PresenterOptions()
IOptions mIOptions;
public void AttachInterface(IOptions pOptions)
{
mIOptions = pOptions;
}
Now in Presenter Options you can modify the tables as you please, as well as fill them..
mIOptions.mProgramOptionsList = mModelOptions.GetProgOptionsFromDB();
This is the class you want to have your table control in. This could be a separate GUI/View class with its own layout and structure. As long as you have attached the Interface (IOptions) to the class your using to hold all your tables.
private IOptions mIOptions;
private BindingSource mbsProgramOptions;
public int mOptionsID { get; set; }
void AttachOptionsInterface(IOptions pOptions)
{
mIOptions = pOptions;
CreateDataBindings();
}
private void CreateDataBindings()
{
mbsProgramOptions= new BindingSource();
mbsProgramOptions.DataSource = mIOptions.mProgramOptionsList; // Or what ever datatable you have made
dgvProgramOptions.AutoGenerateColumns = false;
dgvProgramOptions.DataSource = mbsProgramOptions; // this binds your DataGridView to the DataSource
}
Once this is done not only can you add or change the data to any class you have attached IOptions too you can also display the table anywhere you please by just doing something like (Assuming you called your table control class above TableHelper):
In the PresenterOptions or any class for that matter:
TableHelper ProgramOptionsList;
ProgramOptionsList.mOptionsID = 1234; // Accessing a public/get;set; variable in TableHelper Class
ProgramOptionsList.Text = "Table Title";
ProgramOptionsList.ShowDialog();
ProgramOptionsList.BringToFront(); // Just in case you have multiple tables over lapping each other in TableHelper
I am bit new in asp.net so please forgive me if my question is silly.
Actually I am loading a page(aspx) through window.open. Everything thing is going fine window is coming with the requested page.
This page is having two panels in a same row ie. in two td's.
One panel is for showing data from different kind of source and the other one is for different kind of source.
Now my problem is with this dropdowns. In my page m having around 10 dropdowns, 5 is left side and 5 is for right side.
when I am setting the values to these dropdowns for both side ( left column 5 dropdowns with differnt values and rith column 5 dropdowns with different values).
i have two seperate methods for "selected vlues" for these dropdowns for each side.
Now problem is........whichever method i call last........that values are appearing in the both side of dropdowns. though i used different methods for selecting values.
see the code snippet of the pageload calls...
if (!IsPostBack)
{
// methods for filling all dropdowns-----
FetchData(); // for first side
FetchData_Q2(); // second side
}
private void FetchData()
{
ddlCardType.SelectedValue = "2";
ddlProductType.SelectedValue = "5";
}
private void FetchData_Q2()
{
ddlCardType.SelectedValue = "1";
ddlProductType.SelectedValue = "1";
}
SO here first side(FetchData()) dropdown is also showing the data as like as second side(FetchData_Q2())
HOPE U R GETTING MY PROBLEM.
It would be better if you could post your code.
But as a suggestion, I would say add the dropdownlist in two different reapter controls, then populate the dropdownlist in the ItemDataBound event of the repeater control.
A better alternative would be to use jQuery like this in each td (or your panel):
for(var i = 0;i<5;i++)
{
var options = $("#options");
$.each(data, function() {
options.append($("<option />").val(this.ID).text(this.Name));
});
//append the $("#options") to a parent div
}
where the data could be achieved by using Ajax GET.
If you want to set selected value for dropdownlist, you have to change selectedindex. You can try something like:
private void FetchData()
{
ddlCardType.SelectedIndex = ddlCardType.Items.IndexOf(ddlCardType.Items.FindByValue("2"));
ddlProductType.SelectedIndex = ddlProductType.Items.IndexOf(ddlProductType.Items.FindByValue("5"));
}
private void FetchData_Q2()
{
ddlCardType.SelectedIndex = ddlCardType.Items.IndexOf(ddlCardType.Items.FindByValue("1"));
ddlProductType.SelectedIndex = ddlProductType.Items.IndexOf(ddlProductType.Items.FindByValue("1"));
}
I have an ItemsControl displaying a collection of files. Those files are sorted by most recent modification, and there's a lot of them.
So, I want to initially only show a small part (say, only 20 or so) of them, and display a button labelled "Show More" that would reveal everything when clicked.
I already have a solution, but it involves using a good old LINQ Take on my view model's source property. I was wondering if there was a cleaner way.
Thanks.
Why not have the object that you assign to the ItemsSource handle this logic - on first assignment, it would report a limited subset of the items. When Show More is clicked, the object is updated to show more (or all entries) and then notifies the framework that the property has changed (e.g. using the IPropertyNotifyChanged).
public class MyItemSource
{
private List<string> source = { ... };
public MyItemSource()
{
this.ShowThisMany = 20;
}
public int ShowThisMany
{
get;
set; // this should call\use the INotifyPropertyChanged interface
}
public IEnumerable<string> this[]
{
return this.source.Take(this.ShowThisMany);
}
}
...
MyItemsSource myItemsSource = new MyItemsSource();
ItemsControl.Source = myItemsSource;
...
void OnShowMoreClicked(...)
{
myItemsSource.ShowThisMany = 50;
}
In order to do this, you need to create some sort of 'view' on your data. There is nothing within the WPF framwork that will give you this functionality for free. In my opinion, a simple bit of Linq, Take(), is a clean and simple solution.
I found a question that I belive is what I was looking for, but there were certain things that I was not following in the answers. Therefore, I'd like to ask the question in a different way (Thanks for your patience). Here is the link I am referring to:
How to avoid duplicating logic on two similar WinForms?
OK. I have a dialog that I created. We've got controls for User Input, buttons to display other dialogs (to gain other input), etc. Aesthetically, I prefer the dialog with the controls laid out vertically. Anyhow, I was also thinking of creating a UserControl version of this dialog. This UserControl would have all the same controls, and all the same logic, but the controls would be laid out entirely different (more horizontal, then vertical).
So, I can't just create another (3rd) UserControl that I drop on the orignal form, and on the UserControl I want to create. (This 3rd UserControl would then contain all logic - thus, sharing between the two). I can't do this because of the different layouts.
I have no problem creating the two (Form, UserControl), with the controls laid out differently, but I don't want to 'cut-and-paste' all the logic from one to the other.
This does not seem like a case for MVP, or MVC. My model is the dialog itself. The dialog is intialized with some values, yes, but once initialized the "Model" becomes further User Input (which I then grab when they press the OK button).
Take for example this code (an event for one of my buttons on this dialog):
private void EditQuery_Click(object sender, EventArgs e)
{
try
{
EditQueryParameters();
}
catch (System.Exception ex)
{
// TODO: Write ErrMsg to Log file.
MessageBox.Show("Edit Query Parameters Error:\n\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void EditQueryParameters()
{
if (m_ReportType.QueryScoreDetails && optPickDetail.Checked)
{
// This brings up a different type of dialog
QueryDetails();
return;
}
// DateRange, StartDate, and EndDate are all saved from the last time
// I called this dialog
DateType DtType = new DateType(m_ReportType.DBDateRangeField,
m_DateRange, m_StartDate, m_EndDate);
// StartTime, EndTime too!
TimeType TmType = new TimeType(m_ReportType.DBTimeRangeField,
m_StartTime, m_EndTime);
List<AdvancedFilter> Filters = null;
if (lstAdvancedQuery.Items.Count > 0)
{
Filters = new List<AdvancedFilter>();
}
for (int i = 0; i < lstAdvancedQuery.Items.Count; ++i)
{
Filters.Add((AdvancedFilter)lstAdvancedQuery.Items[i]);
}
// QueryType is also saved from the last time I called QueryBuilder
QueryBuilder QryBuilder = new QueryBuilder(m_ReportType.DBCatalog, m_ReportType.DBTable,
m_QueryType, ref DtType, ref TmType, ref Filters);
// I am using Visual WebGUI, I have to do it this way
QryBuilder.Closed += new EventHandler(QryBuilder_Closed);
QryBuilder.ShowDialog();
}
I mean, I suppose I could have some "logic" class, which exposes something like:
public void EditQueryParameters(ref ReportType RptType, bool PickDetail,
string DateRange, DateTime StartDate, DateTime EndDate,
DateTime StartTime, DateTime EndTime, string QueryType)
{
if (ReportType.QueryScoreDetails && PickDetail)
{
// This brings up a different type of dialog
QueryDetails();
return;
}
DateType DtType = new DateType(ReportType.DBDateRangeField,
DateRange, StartDate, EndDate);
TimeType TmType = new TimeType(ReportType.DBTimeRangeField,
StartTime, EndTime);
// Yikes, more stuff to add to the signature of my method
// Will have to pull this outside the method and pass in Filters
List<AdvancedFilter> Filters = null;
if (lstAdvancedQuery.Items.Count > 0)
{
Filters = new List<AdvancedFilter>();
}
for (int i = 0; i < lstAdvancedQuery.Items.Count; ++i)
{
Filters.Add((AdvancedFilter)lstAdvancedQuery.Items[i]);
}
// QueryType is also saved from the last time I called QueryBuilder
QueryBuilder QryBuilder = new QueryBuilder(ReportType.DBCatalog, ReportType.DBTable,
QueryType, ref DtType, ref TmType, ref Filters);
// I am using Visual WebGUI, I have to do it this way
QryBuilder.Closed += new EventHandler(QryBuilder_Closed);
QryBuilder.ShowDialog();
}
There's a lot of set-up to use this method. I don't know, maybe I'm looking for something more .. "slick"?
On top of that, look at some (not all) of my init code (this is called from constructor or form_Load; it doesn't seem worth it to add this to the logic class, so that's all still "cut and paste" between the two):
private void InitializeUserDefinedTitle()
{
txtUserTitle.Text = m_UserTitle;
}
private void InitializePrintSelectionCriteria()
{
// Print Selection Criteria
chkSelectionCriteria.Checked = m_printSelectionCriteria;
}
private void InitializeTrendBy()
{
cmbTrend.Items.AddRange(Enum.GetNames(typeof(TrendBy)));
cmbTrend.SelectedIndex = (int)m_TrendBy;
cmbTrend.Visible = m_ReportType.TrendVisible;
lblTrend.Visible = m_ReportType.TrendVisible;
}
In summary, the original WinForm is a dialog that is intialized with data (constructor), is displayed to the user for input, when they OK the dialog that data is retrieved (and that data is stored outside the dialog, in member variables, for the next time they call the dialog - this is because we want to show what they last picked/entered).
That type of dialog I just described will also be a user control, and the logic should be shared between the two.
Thanks.
You can make two controls A and B, each containing the same buttons and/or other input controls arranged differently. Controls A and B will have identical properties, and events. The form (or third control) will contain the event handlers that allow the logic to be contained in only one place.
You can display either control A or B using the visible property or by adding one to the container.controls property, the container being the containing form or control.
And, for example, instead of having a handler for button1 in controls A and B that handles the complete logic of the button press, the handlers for button1 in control A and B would just raise an event that will be handled by the container of control A or B.
Instead of encapsulating the logic, I would encapsulate the layout. Use a property of the user control to specify which layout yout want. Then wherever it is (standalone form, one of three instances on the same form, whatever) you access it and specify the layout the same way.
As for how to encapsulate the layout, there are a bunch of possibilities. You could just do it programatically, i.e. write each version of the layout code. (The programamatic version would be cleaner if you used some kind of layout containers, like the Panels in WPF.) You could draw the layout in a designer, and copy the generated code. The different versions of the layout logic could be stuffed into private methods, or encapsulated into objects.