TreeView Nodes appear to be caching - c#

I'm creating a custom web user control in c#. It is intended to interact with a permission hierarchy. We have different "sites" and each site has many "apps" and each app has many "permissions"
So, We have a TabPanel that loads a tab for each site. Then in each tab we have a TreeView where the parent nodes are the apps and the inner nodes are the permissions.
The Permissions show check boxes based on some criteria and are checked based on whether or not the HasPermission function returns true.
All of this code works...but only for the first user selected. For any subsequent user chosen, a step through the debugger shows all the correct logic being executed, but the page displays the same information as that of the first user selected.
So basically, it's saving the display somewhere...and I'm at a loss to find out where.
public partial class Permissions : System.Web.UI.UserControl
{
string _NTLogin;
CoreUser _User;
bool _IsAdmin;
public string NTLogin
{
get
{
return _NTLogin;
}
set
{
ViewState["NTLogin"] = value;
_NTLogin = value;
}
}
public bool IsAdmin
{
get
{
return _IsAdmin;
}
set
{
ViewState["IsAdmin"] = value;
_IsAdmin = value;
}
}
protected void Page_Load(object sender, EventArgs e)
{
}
public void LoadTabs()
{
string [] sites = MISCore.BusinessLayer.CorePermission.GetSites();
foreach (string site in sites)
{
TabPanel tp = new TabPanel();
tp.HeaderText = site;
TabContainer1.Tabs.Add(tp);
}
}
public void LoadTrees()
{
if(_User == null)
return;
TabPanelCollection tabs = TabContainer1.Tabs;
foreach (TabPanel tab in tabs)
{
string site = tab.HeaderText;
string[] apps = MISCore.BusinessLayer.CorePermission.GetApplications(site);
TreeView tv1 = new TreeView();
tv1.EnableViewState = false;
foreach (string app in apps)
{
TreeNode tn1 = new TreeNode(app);
tn1.SelectAction = TreeNodeSelectAction.None;
string[] perms = MISCore.BusinessLayer.CorePermission.GetPermissions(site, app);
foreach (string perm in perms)
{
TreeNode tcn1 = new TreeNode(perm);
tcn1.SelectAction = TreeNodeSelectAction.None;
if (IsAdmin || _User.Manager.HasPermission(site, app, perm))
{
tcn1.ShowCheckBox = true;
if (_User.HasPermission(site, app, perm))
{
tcn1.Checked = true;
}
else
{
tcn1.Checked = false;
}
}
else
{
tcn1.ShowCheckBox = false;
}
tn1.ChildNodes.Add(tcn1);
}
tv1.Nodes.Add(tn1);
}
tab.Controls.Add(tv1);
}
}
protected override void LoadViewState(object savedState)
{
base.LoadViewState(savedState);
_NTLogin = (string)ViewState["NTLogin"];
_IsAdmin = (bool)ViewState["IsAdmin"];
if(_NTLogin != null)
_User = new CoreUser(_NTLogin);
TabContainer1.Tabs.Clear();
LoadTabs();
LoadTrees();
}
}
[UPDATE]
I iterate through the treeview after all the above code, it correctly stores their correct status. This is an issue with displaying. I can successfully change any other property, tooltip, text, etc to display their state, but the checkboxes are not updating...

I would use Fiddler to see who is caching the results. By looking at the requests you'll be able to tell if it's the browser or the server causing the problem.

Or if its okay with your client, you can put in a small link button that says refresh, and either you or the user can force this refresh treeview method, whenever required.

Should be pretty simple, in the paramters for the tab just add EnableViewState = false. Let me know if this works for you.

Related

Contextual action bar set a button to invisible

I have implemented a custom contextual action bar with two buttons : one for deleting selected items from a listview and the other one for editing selected item . What I am trying to do is to make the editButton invisible when two or more items have been selected. I tried doing it this way but nothing happens:
public void OnItemCheckedStateChanged (ActionMode mode, int position, long id, bool check)
{
SetSubtitle (mode);
if (listview.CheckedItemCount > 1) {
disableButtonFlag = true;
} else
disableButtonFlag = false;
self.InvalidateOptionsMenu();
}
public bool OnCreateActionMode (ActionMode mode, IMenu menu)
{
self.MenuInflater.Inflate (Resource.Menu.CAB_menu, menu);
if (disableButtonFlag) {
menu.FindItem(Resource.Id.action_edit).SetVisible(false);
} else {
menu.FindItem(Resource.Id.action_edit).SetVisible(true);
}
mode.Title = "Select Items";
SetSubtitle (mode);
return true;
}
This is how handling multiple items works for me:
private void listView_SelectedIndexChanged(object sender, EventArgs e)
{
if(listView.SelectedIndices.Count > 1)
{
MessageBox.Show("Multiple rows selected!");
}
}
If selected index changes, check for how many indices are checked. If more than 1 (=multiple), fire your code.
Finally I found my mistake! It was that instead of declaring:
if (listview.CheckedItemCount > 1) {
disableButtonFlag = true;
} else
disableButtonFlag = false;
within my OnCreateActionMode method and calling Activity.InvalidateOptionsMenu() in my OnItemCheckedStateChanged()method I should have declared these rows within my OnPrepareActionMode() method and then called ActionMode.Invalidate() within the OnItemCheckedStateChanged()method.

Minimize coding for validation in C#

I'm trying to validate a set of Textboxes in a winform application.
if(string.IsNullOrEmpty(txtCarbohydrate.Text){
//todo
}
but there are several Textboxes in my form to be validated for emptiness , not only in the current win form but other forms too. how can i create a method or a class that can validate several Textboxes and
be reusable across application?
EDIT : i wrote somthing like this , any suggestion to make it better ?
class ValidateEmpty
{
bool res = false;
//List<object> txt = new List<object>();
List<string> st = new List<string>();
public List<string> St
{
get { return st; }
set { st = value; }
}
public ValidateEmpty(List<string> _str)
{
this.st = _str;
}
public bool checkEmpty()
{
bool res = false;
for (int i = 0; i < St.Count(); i++ )
{
if(string.IsNullOrEmpty(St[i]))
{
res= true;
}
}
return res;
}
}
}
`
You could put them in a list and then loop through the list.
List<TextBox> TextBoxes=new List<TextBox>() {txtCarbohydrate, txtProtein, txtFat};
foreach(TextBox tb in TextBoxes)
{
if(String.IsNullOrEmpty(tb.Text)
{
//do something
}
}
Based on your edit, you want to return a Boolean (it's really hard to understand your code and what you're trying to accomplish, you need to be clear and concise!) to indicate if a TextBox was empty or not. Here's how you could create a method to do that...
public static bool IsThereAnEmptyTextBox(List<TextBox> textBoxes)
{
bool emptyfound=false;
foreach(TextBox tb in textboxes)
{
if(String.IsNullOrEmpty(tb.Text)
{
emptyfound=true;
}
}
return emptyfound;
}
You can call this function from any class, if you put this function in a Utility class or in a base class etc. If you want to combine it with paqogomez's answer you can call it from a form like this...
bool emptyfound=MyUtilities.IsThereAnEmptyTextBox(myForm.Controls.OfType<TextBox>().ToList());
I think this is a terrible way of going about it, but I'm trying to demonstrate how you could do what you've asked for.
To grab all textboxes in a single form use Controls.OfType<T>
var controls = myForm.Controls.OfType<TextBox>();
foreach(TextBox tb in controls)
{
//do validation
}
Depending on the type of validation you are doing, you can also do as #RandRandom suggests and put the required attribute on your textboxes. This will force the user to put text in before its submitted.

Cannot find instance of dynamically added UserControl .Net

I have a UserControl which I am loading into a div which is inside an UpdatePanel. Here is my code for loading it:
controls.IDLControl IdlControl = LoadControl(#"~/controls/IDLControl.ascx") as controls.IDLControl;
IdlControl.ClientIDMode = ClientIDMode.Static;
IdlControl.ID = "IDLControl";
spGroup.Controls.Clear();
spGroup.Controls.Add(IdlControl);
And here is my code for trying to retrieve an instance of it:
controls.IDLControl IdlControl = RecursiveFindControl(this, "IDLControl") as controls.IDLControl;
private Control RecursiveFindControl(Control targetControl, string findControlId) {
if (targetControl.HasControls()) {
foreach (Control childControl in targetControl.Controls) {
if (childControl.ID == findControlId) {
return childControl;
}
RecursiveFindControl(childControl, findControlId);
}
}
return null;
}
But, all I get is null. I need help on figuring this out.
AFAIK, I need to re-add the control to the page on pre-init but it is one of the controls that can be added depending on which option is selected from a drop down list (which also is filled dynamically). I am stuck trying to figure out how to make this work.
You can try something like this to add your control back in the Page_Init based on the option selected in your DropDownList.
protected void Page_Init(Object sender, EventArgs e)
{
if (IsPostBack)
{
if (drpYourDropDown.Items.Count > 0 && drpYourDropDown.SelectedItem.Text == "yourOption")
{
AddIDLControl();
}
}
}
private void AddIDLControl()
{
controls.IDLControl IdlControl = LoadControl(#"~/controls/IDLControl.ascx") as controls.IDLControl;
IdlControl.ClientIDMode = ClientIDMode.Static;
IdlControl.ID = "IDLControl";
spGroup.Controls.Clear();
spGroup.Controls.Add(IdlControl);
}

Sitecore Rich Text editor customisation of link Insertions

When a user uses the "Insert Link" feature on the RTE to create stories, we get something like...<Item-Name-Of-Story
Instead of taking the Item name I would like to use another field called "Headline"
Does anyone know how to do this?...
Headline-Of-Story
Any help will be much appreciated. Thanks
First of all, you need need to look at this class with Reflector or DotPeek : Sitecore.Shell.Controls.RichTextEditor.InsertLink.InsertLinkForm and to modify it with your own class.
You need to modify just this method,I tested and works fine :
protected override void OnOK(object sender, EventArgs args)
{
Assert.ArgumentNotNull(sender, "sender");
Assert.ArgumentNotNull((object) args, "args");
string displayName;
string text;
if (this.Tabs.Active == 0 || this.Tabs.Active == 2)
{
Item selectionItem = this.InternalLinkTreeview.GetSelectionItem();
if (selectionItem == null)
{
SheerResponse.Alert("Select an item.", new string[0]);
return;
}
else
{
displayName = selectionItem["Headline"];
if (selectionItem.Paths.IsMediaItem)
text = CustomInsertLinkForm.GetMediaUrl(selectionItem);
else if (!selectionItem.Paths.IsContentItem)
{
SheerResponse.Alert("Select either a content item or a media item.", new string[0]);
return;
}
else
{
LinkUrlOptions options = new LinkUrlOptions();
text = LinkManager.GetDynamicUrl(selectionItem, options);
}
}
}
else
{
MediaItem mediaItem = (MediaItem) this.MediaTreeview.GetSelectionItem();
if (mediaItem == null)
{
SheerResponse.Alert("Select a media item.", new string[0]);
return;
}
else
{
displayName = mediaItem.DisplayName;
text = CustomInsertLinkForm.GetMediaUrl((Item) mediaItem);
}
}
if (this.Mode == "webedit")
{
SheerResponse.SetDialogValue(StringUtil.EscapeJavascriptString(text));
base.OnOK(sender, args);
}
else
SheerResponse.Eval("scClose(" + StringUtil.EscapeJavascriptString(text) + "," + StringUtil.EscapeJavascriptString(displayName) + ")");
}
After you modify this class you need to modify next file:
\sitecore\shell\Controls\Rich Text Editor\InsertLink\InsertLink.xml where you need to change codeBeside section
<CodeBeside Type="Sitecore.Shell.Controls.RichTextEditor.InsertLink.InsertLinkForm,Sitecore.Client"/>
with something like :
<CodeBeside Type="YourNameSpace.YourInsertLinkForm,YourAssembly"/>
The simplest way around this would be to type the desired link text, then select this before clicking 'insert link' - this way your hyperlink will have the text of whatever you entered, instead of defaulting to the item name.
If you want to modify how Sitecore renders links in RTE fields, you would need to modify the <renderField> pipeline - if you search for this in the web.config, you will see the different classes involved here. Using dotPeek you can decompile the Sitecore source to see how this works. Potentially you could then create your own renderField pipeline handler to change the link rendering behaviour and then reference this new class in your web.config.

Programmatically adding two buttons to each row as it loads

I've created a ListView in a new WPF window and also a function that populates the ListView when it is called. This function just takes the URL of my web server where I've stored the data, increments the "id" and gets the data and stores it in the ListView. Therefore it populates the ListView with a certain number of items.
The problem I'm facing is that I want to add two buttons, ON & OFF, to each ListView item as it gets populated programmatically. i.e, if 16 items are added, I want 2 buttons for each item, and if it's 12 items, the similar procedure. Here's my code:
namespace user_login
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
Window1 W = new Window1();
public MainWindow()
{
InitializeComponent();
}
public void populate()
{
int i;
int num = 16;
for (i = 1; i <= num; i++)
{
string val = Convert.ToString(i);
string currentUrl = "http://xpleria.com/devices.php?query=dev&id=";
string newUrlWithChangedSort = ReplaceQueryStringParam(currentUrl, "id", val);
string result = getcontent(newUrlWithChangedSort);
W.list1.Items.Add(result);
}
}
public string getcontent(string URL)
{
string content = "";
// Get HTML data
WebClient client = new WebClient();
try
{
content = client.DownloadString(URL);
}
catch (Exception)
{
System.Windows.Forms.MessageBox.Show("No Connection detected!!!");
}
return content;
}
public static string ReplaceQueryStringParam(string currentPageUrl, string paramToReplace, string newValue)
{
string urlWithoutQuery = currentPageUrl.IndexOf('?') >= 0
? currentPageUrl.Substring(0, currentPageUrl.IndexOf('?'))
: currentPageUrl;
string queryString = currentPageUrl.IndexOf('?') >= 0
? currentPageUrl.Substring(currentPageUrl.IndexOf('?'))
: null;
var queryParamList = queryString != null
? HttpUtility.ParseQueryString(queryString)
: HttpUtility.ParseQueryString(string.Empty);
if (queryParamList[paramToReplace] != null)
{
queryParamList[paramToReplace] = newValue;
}
else
{
queryParamList.Add(paramToReplace, newValue);
}
return String.Format("{0}?{1}", urlWithoutQuery, queryParamList);
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
string user = textbox1.Text;
string password = textbox2.Password;
string currentUrl = "http://xpleria.com/login.php?query=login&user=wcam&pass=wireless";
string newUrlWithChangedSort = ReplaceQueryStringParam(currentUrl, "user", user);
string newUrl = newUrlWithChangedSort;
string FinalUrl = ReplaceQueryStringParam(newUrl, "pass", password);
string result= getcontent(FinalUrl);
string value = result.Substring(0, 8);
string invalid = "xpleria0";
string valid = "xpleria1";
if (value.Equals(invalid))
{
System.Windows.MessageBox.Show("The Username and/or Password you have entered is invalid, please try again");
}
else if (value.Equals(valid))
{
string sessionID = result.Substring(8, 32);
System.Windows.MessageBox.Show("HI, WELCOME CLETA");
this.Close();
using (new user_login.loading.PleaseWait(this.Location))
{
W.Show();
populate();
}
}
}
public System.Drawing.Point Location { get; set; }
}
}
I'm going to recommend you take a step back and start giving some serious consideration to organizing your code. I realize this isn't an answer to the question you asked but it is the answer to the question you should be asking.
First of all, all code relating to the retrieval of these items from the URL should be moved into a class of some kind. This class should accept the URL string as a constructor parameter and gather all the appropriate data. You should then create another class which you will use to populate with the data for each individual item and then expose this list. By the time you're done the code in your window should little more complex than:
var ItemsGetter = new ItemsGetter(URL);
foreach(var Item in ItemsGetter.Items)
{
// Populate the ListView
}
Once you're done with that I recommend you create a UserControl. User controls are extremely useful in situations where you need to represent a dynamic number of data entities each with their own set of controls which allow operations to be performed on each one. You should create a UserControl with a label and the two buttons you need. The UserControl's constructor should expect a parameter of the data type you created to represent each one of your classes. From there you can have the buttons operate on the data type as necessary.
Finally, you'll probably need a way to have the UserControl interact with the Window. Say for example one of your buttons is "Delete". You'd probably want the item to disappear from the list once the operation is complete. Don't be tempted to tie in your control with the Window by passing it as a parameter or something. Instead, read up on Action events and learn how you can create an event on the user control which you bind in the foreach loop of the Window when you're populating the list view. When the UserControl has completed the delete operation triggered by the button you can raise the UserControl's event which will prompt the Window to remove the control from the List View.
Last but not least, NAME YOUR CONTROLS.
Hopefully this helps.

Categories

Resources