When the following function is called, it is not showing the corresponding photoBoxes. I've done a debugging walkthrough, it even reaches the parts necessary to Show() and Hide(). I don't know what I can do. It's not showing anything
public void SmokerTakeIngredientFromTable(agents agent, List<smokers> smoker)
{
int index = 0;
bool smoker_takes_ingredients = false;
while (!smoker_takes_ingredients)
{
if ((smoker[index].item != agent.item_1) && (smoker[index].item != agent.item_2))
{
if (index == 0)
{
leftarrow_img.Show();
rightarrow_img.Hide();
downarrow_img.Hide();
}
else if (index == 1)
{
leftarrow_img.Hide();
rightarrow_img.Show();
downarrow_img.Hide();
}
else if (index == 2)
{
leftarrow_img.Hide();
rightarrow_img.Hide();
downarrow_img.Show();
}
agent.item_1 = 3;
agent.item_2 = 3;
break;
}
index++;
}
}
This is what the designer for these photoBoxes look like:
This is the properties page for one of the photoBoxes (they are all identical apart from the actual image file, they all have Visible = false too)
When making visibility changes I need to refresh the form using this.Refresh()
Related
I have an array of toggles defined in script. They are all turned off in the beginning. When the user clicks on one of the toggles, that toggle should be turned on and the other toggles should be switched to off state. Basically there could be only "one" on state toggle. How do I achieve this?
Currently with this script, all the toggles are getting turned off when the user clicks on one of it.
public Toggle[] toggle;
void Start () {
for (int i = 0; i < toggle.Length; i++) {
int idx = i;
toggle[idx].onValueChanged.AddListener (delegate {
ToggleValueChanged (toggle[idx], idx);
});
}
}
public void ToggleValueChanged (Toggle change, int index) {
for (int i = 0; i < toggle.Length; i++) {
if (i == index) {
return;
} else {
if (toggle[i].isOn) {
toggle[i].isOn = false;
}
}
}
}
Unity has a component called ToggleGroup that allow you to do just that.
ToggleContainer Parent Object:
Reference ToggleGroup object in every Toggle component as following:
Scene Hierarchy:
Overview:
https://gfycat.com/bossyscenteddorado
Change your ToggleValueChanged function like this :
public void ToggleValueChanged (Toggle change, int index)
{
for (int i = 0; i < toggle.Length; i++)
{
if (i == index) continue;
if (toggle[i].isOn) {
toggle[i].isOn = false;
}
}
}
When you return in you first if statement, other toggles won't get off. you have to continue iterating your loop.
And instead getting the index and passing it to the delegate, you can use RefrenceEqual
EDIT
Actually each time you manipulate the toggle[i].isOn, you are changing the value of it. So each time, You are calling your function.
EDIT
try this :
public void ToggleValueChanged (Toggle change, int index)
{
for (int i = 0; i < toggle.Length; i++)
{
if (i == index) continue;
if (toggle[i].isOn)
{
toggle[i].SetIsOnWithoutNotify(false);
}
}
}
Why do you even need the index for this?
Simply do
public void ToggleValueChanged (Toggle change)
{
// add a little safety to actually only disable all others if
// this one ws actually enabled
if(!change.isOn) return;
foreach(var toggle in toggles)
{
if (toggle == change) continue;
if (toggle.isOn)
{
// I would actually specifically NOT use "SetIsOnWithoutNotify"
// because you never know who else is actually listening to the state change
// so if you simply set it to false but don't invoke the callback events
// things might behave different than expected
toggle[i].isOn = false;
}
}
}
and accordingly
foreach(var t in toggle)
{
var currentToggle = t;
currentToggle .onValueChanged.AddListener(value => ToggleValueChanged(currentToggle));
}
There is no need to either return or continue, just don't handle the toggle if it's the indexth one:
public void ToggleValueChanged (Toggle change, int index)
{
for (int i = 0; i < toggle.Length; i++)
{
if (i != index)
{
toggle[i].isOn = false;
}
}
}
Also you can assume that all others are off, so no reason to check that either.
If they are mutually exclusive, they aren't "boolean states", it's just one state, supported by an enum and including the null value. If your UI is a set of checkboxes, you should switch it to a set of radio buttons. A dropdown box would do as well.
I have a custom renderer in my iOS Native code for my main page. It works perfectly fine when the app start up, and renders Navbar items using the iOS System icons which is what I want. However, if I navigate away from the main page, when I navigate back the RightBarButtonItems array only contains two uninstantiated objects, I put in a check (RightNavItems.Title == null) to continue when this was the case to see what would happen, and indeed the items are not rendered, if I navigate away and back again the app crashes since the RightBarButtonItems array is now empty.
Why is it that the toolbar items are uninitialised when navigating back to the main page? What is the proper way to deal with navigation in a custom renderer like this?
Here is the code for the custom renderer:
public class ItemsPageRenderer : PageRenderer
{
public new ItemsPage Element
{
get { return (ItemsPage)base.Element; }
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
var rightNavList = new List<UIBarButtonItem>();
var navigationItem = this.NavigationController.TopViewController.NavigationItem;
for (var i = 0; i < Element.ToolbarItems.Count; i++)
{
var reorder = (Element.ToolbarItems.Count - 1);
var ItemPriority = Element.ToolbarItems[reorder - i].Priority;
UIBarButtonItem RightNavItems = navigationItem.RightBarButtonItems[i];
if (RightNavItems.Title == null)
continue;
if (RightNavItems.Title.ToLower() == "add")
{
rightNavList.Add(new UIBarButtonItem(UIBarButtonSystemItem.Add)
{
Action = RightNavItems.Action,
Target = RightNavItems.Target
});
}
else if (RightNavItems.Title.ToLower() == "edit")
{
rightNavList.Add(new UIBarButtonItem(UIBarButtonSystemItem.Edit)
{
Action = RightNavItems.Action,
Target = RightNavItems.Target
});
}
else
{
rightNavList.Add(RightNavItems);
}
}
navigationItem.SetRightBarButtonItems(rightNavList.ToArray(), false);
}
}
Check this code snippet
var rightNavList = new List<UIBarButtonItem>();
var navigationItem = this.NavigationController.TopViewController.NavigationItem;
for (var i = 0; i < Element.ToolbarItems.Count; i++)
{
var reorder = (Element.ToolbarItems.Count - 1);
var ItemPriority = Element.ToolbarItems[reorder - i].Priority;
UIBarButtonItem RightNavItems = navigationItem.RightBarButtonItems[i];
if (RightNavItems.Title == null)
continue;
if (RightNavItems.Title.ToLower() == "add")
{
rightNavList.Add(new UIBarButtonItem(UIBarButtonSystemItem.Add)
{
Action = RightNavItems.Action,
Target = RightNavItems.Target
});
}
else if (RightNavItems.Title.ToLower() == "edit")
{
rightNavList.Add(new UIBarButtonItem(UIBarButtonSystemItem.Edit)
{
Action = RightNavItems.Action,
Target = RightNavItems.Target
});
}
else
{
rightNavList.Add(RightNavItems);
}
}
navigationItem.SetRightBarButtonItems(rightNavList.ToArray(), false);
You change the item appearance from title to icon when first entering the page , however , when second entering the page , the condition RightNavItems.Title == null is true , so it jump out the loop without adding any item to the list , so navigationItem.SetRightBarButtonItems add a null array at last.
Solution
Modify as below
if (RightNavItems.Title == null)
{
rightNavList.Add(RightNavItems); //add this line.
continue;
}
I have a tabcontrol with 9 tabitems in it. Each tab has as series of TextBoxes for the user to enter data. At the bottom is a clear button, hooked up to this method:
public void ClearTextBoxes()
{
ChildControls ccChildren = new ChildControls();
foreach (object o in ccChildren.GetChildren(rvraDockPanel, 2))
{
if (o.GetType() == typeof(WatermarkTextBox) || o.GetType() == typeof(DateBox) ||
o.GetType() == typeof(DigitBox) || o.GetType() == typeof(PhoneBox))
{
WatermarkTextBox water = (WatermarkTextBox)o;
water.Text = "";
}
else if (o.GetType() == typeof(ComboBox))
{
ComboBox combo = (ComboBox)o;
combo.SelectedIndex = -1;
}
else if (o.GetType() == typeof(CheckBox))
{
CheckBox check = (CheckBox)o;
check.IsChecked = false;
}
}
}
This works perfectly fine, however I also have a MenuItem that allows the user to ClearAll tabs. Right now the clear button only clears what's on the currently selected tab, and leaves everything else alone. My thought on how to do this was to iterate through the tabitems with this loop:
for (int i = 0; i < 10; i++ )
{
tabSelection.SelectedIndex = i;
clearButton_Click(null, null);
}
It will flip through all the tabs, but won't clear anything. I have tried using Automation instead, with the same result. It just won't seem to clear anything.
ChildControls class:
class ChildControls
{
private List<object> listChildren;
public List<object> GetChildren(Visual p_vParent, int p_nLevel)
{
if (p_vParent == null)
{
throw new ArgumentNullException("Element {0} is null!", p_vParent.ToString());
}
this.listChildren = new List<object>();
this.GetChildControls(p_vParent, p_nLevel);
return this.listChildren;
}
private void GetChildControls(Visual p_vParent, int p_nLevel)
{
int nChildCount = VisualTreeHelper.GetChildrenCount(p_vParent);
for (int i = 0; i <= nChildCount - 1; i++)
{
Visual v = (Visual)VisualTreeHelper.GetChild(p_vParent, i);
listChildren.Add((object)v);
if (VisualTreeHelper.GetChildrenCount(v) > 0)
{
GetChildControls(v, p_nLevel + 1);
}
}
}
}
WPF discards the entire VisualTree of a TabItem which isn't selected, so no controls actually exist on tabs that are not visible.
To maintain control values (such as Selections, Text, etc), they need to be bound to something. If they're bound to something then your Clear() method should actually clear the Bound values, not the UI values. If they're not bound to anything, then the TabControl will revert to its initial state when selected.
To get your code working you need to add the following line to your cleanup method:
tabControl.SelectedIndex = i;
--> UpdateLayout();
Button_Click(null, null);
The UpdateLayout method takes care that the TabItem is drawn and the VisualTree is available afterwards.
Generally this approach isn't nice and if you have a real Application with Business data behind I'd recommend you have a look at databinding/MVVM. The approach shouldn't be to reset your controls in the view, but to reset your bound business data in the background.
I have a Navigation-bar in my program that allows you to navigate the different sections in my TextBox, but the problem I have is that this doesn't work if the Text I am scrolling to is already visible on the screen.
Like in this example, if I try to jump from Section 1 to Section 3, it won't work as it's already visible.
But, in this example if I jump to Section 3, it works fine as it's not already visible.
The scrolling function I use is very simple:
if (nLine > 0 && nLine <= textBox.LineCount)
textBox.ScrollToLine(nLine - 1);
I hope that someone can shed some light on an alternative solution that allows me to scroll even if the text is already visible.
Edit: Added solution.
This is a code snippet from my project.
private static void ScrollToLineCallback(DependencyObject target, DependencyPropertyChangedEventArgs e)
{
var textBox = (TextBox)target;
int newLineValue;
if (Int32.TryParse(e.NewValue.ToString(), out newLineValue))
{
if (newLineValue > 0 && newLineValue <= textBox.LineCount) // Validate
{
textBox.ScrollToLine(newLineValue - 1); // Scroll to Line
// Check and see if we are at the line we want.
if (textBox.GetFirstVisibleLineIndex() <= newLineValue && textBox.GetLastVisibleLineIndex() >= newLineValue)
{
// If not lets move to the desired location
int newLineCorrectionValue = newLineValue - textBox.GetFirstVisibleLineIndex() - 2; // How much further do we need to scroll down?
for (int i = 0; i < newLineCorrectionValue; i++)
{
textBox.LineDown(); // Scroll down
}
}
}
}
}
You could use GetCharacterIndexFromLineIndex to get the index of the beginning of the desired line and then set the CaretIndex to that value.
Because I don't really know, what you are trying to achieve, another possibility is to use LineUp and LineDown in conjunction with GetFirstVisibleLineIndex and GetLastVisibleLineIndex.
private void TextBoxGotoLine(
TextBox textbox1,
int linenum)
{
var target_cpos = textbox1.GetCharacterIndexFromLineIndex(linenum);
var target_char_rect = textbox1.GetRectFromCharacterIndex(target_cpos);
var first_char_rect = textbox1.GetRectFromCharacterIndex(0);
textbox1.ScrollToVerticalOffset(
target_char_rect.Top -
first_char_rect.Top
);
}
I found out if Wrapping is enabled its more complications:
private void TextBoxGotoLine(TextBox textbox1, int linenum)
{
// int Linenum is the Absolute Line, not including
// effect of Textbox Wrapping.
if (textbox1.TextWrapping == TextWrapping.Wrap)
{
// If textbox Wrapping is on, we need to
// Correct the Linenum for Wrapping which adds extra lines
int cidx = 0;
bool found = false;
int ln = 0;
char[] tmp = textbox1.Text.ToCharArray();
for (cidx = 0; cidx < tmp.Length; cidx++)
{
if (tmp[cidx] == '\n')
{
ln++;
}
if (ln == linenum)
{
found = true;
break;
}
}
if (!found)
return;
linenum = textbox1.GetLineIndexFromCharacterIndex(cidx+1);
}
// Non-Wrapping TextBox
var target_cpos = textbox1.GetCharacterIndexFromLineIndex(linenum);
var target_char_rect = textbox1.GetRectFromCharacterIndex(target_cpos);
var first_char_rect = textbox1.GetRectFromCharacterIndex(0);
textbox1.ScrollToVerticalOffset(target_char_rect.Top - first_char_rect.Top);
}
I'm using Asp.Net 2.0. I have a scenario where i need to check a user input against any of two ranges. For e.g. I need to check a textbox value against ranges 100-200 or 500-600. I know that i can hook up 2 Asp.Net RangeValidators to the TextBox, but that will try to validate the input against both the ranges, an AND condition,if you will. CustomValidator is an option, but how would I pass the 2 ranges values from the server-side. Is it possible to extend the RangeValidator to solve this particular problem?
[Update]
Sorry I didn't mention this, the problem for me is that range can vary. And also the different controls in the page will have different ranges based on some condition. I know i can hold these values in some js variable or hidden input element, but it won't look very elegant.
A CustomValidator should work. I'm not sure what you mean by "pass the 2 ranges values from the server-side". You could validate it on the server-side using a validation method like this:
void ValidateRange(object sender, ServerValidateEventArgs e)
{
int input;
bool parseOk = int.TryParse(e.Value, out input);
e.IsValid = parseOk &&
((input >= 100 || input <= 200) ||
(input >= 500 || input <= 600));
}
You will then need to set the OnServerValidate property of your CustomValidator to "ValidateRange", or whatever you happen to call it.
Is this the sort of thing you're after?
I do not believe this is possible using the standard RangeValidator control.
I did some searching and I believe your best solution is going to be to create your own CustomValidator control which you can include in your project to handle this scenario.
http://www.dotnetjunkies.ddj.com/Article/592CE980-FB7E-4DF7-9AC1-FDD572776680.dcik
You shouldn't have to compile it just to use it in your project, as long as you reference it properly.
You can use the RegularExpressionValidator with the ValidationExpression property set to
Edit: (whoops, 650 and 201 etc. were valid with the old pattern)
^(1\d{2}|200|5\d{2}|600)$
This will test the entered text for 100-200 and 500-600.
I extended the BaseValidator to achieve this. Its fairly simple once you understand how Validators work. I've included a crude version of code to demonstrate how it can be done. Mind you it's tailored to my problem(like int's should always be > 0) but you can easily extend it.
public class RangeValidatorEx : BaseValidator
{
protected override void AddAttributesToRender(System.Web.UI.HtmlTextWriter writer)
{
base.AddAttributesToRender(writer);
if (base.RenderUplevel)
{
string clientId = this.ClientID;
// The attribute evaluation funciton holds the name of client-side js function.
Page.ClientScript.RegisterExpandoAttribute(clientId, "evaluationfunction", "RangeValidatorEx");
Page.ClientScript.RegisterExpandoAttribute(clientId, "Range1High", this.Range1High.ToString());
Page.ClientScript.RegisterExpandoAttribute(clientId, "Range2High", this.Range2High.ToString());
Page.ClientScript.RegisterExpandoAttribute(clientId, "Range1Low", this.Range1Low.ToString());
Page.ClientScript.RegisterExpandoAttribute(clientId, "Range2Low", this.Range2Low.ToString());
}
}
// Will be invoked to validate the parameters
protected override bool ControlPropertiesValid()
{
if ((Range1High <= 0) || (this.Range1Low <= 0) || (this.Range2High <= 0) || (this.Range2Low <= 0))
throw new HttpException("The range values cannot be less than zero");
return base.ControlPropertiesValid();
}
// used to validation on server-side
protected override bool EvaluateIsValid()
{
int code;
if (!Int32.TryParse(base.GetControlValidationValue(ControlToValidate), out code))
return false;
if ((code < this.Range1High && code > this.Range1Low) || (code < this.Range2High && code > this.Range2Low))
return true;
else
return false;
}
// inject the client-side script to page
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
if (base.RenderUplevel)
{
this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "RangeValidatorEx", RangeValidatorExJs(),true);
}
}
string RangeValidatorExJs()
{
string js;
// the validator will be rendered as a SPAN tag on the client-side and it will passed to the validation function.
js = "function RangeValidatorEx(val){ "
+ " var code=document.getElementById(val.controltovalidate).value; "
+ " if ((code < rangeValidatorCtrl.Range1High && code > rangeValidatorCtrl.Range1Low ) || (code < rangeValidatorCtrl.Range2High && code > rangeValidatorCtrl.Range2Low)) return true; else return false;}";
return js;
}
public int Range1Low
{
get {
object obj2 = this.ViewState["Range1Low"];
if (obj2 != null)
return System.Convert.ToInt32(obj2);
return 0;
}
set { this.ViewState["Range1Low"] = value; }
}
public int Range1High
{
get
{
object obj2 = this.ViewState["Range1High"];
if (obj2 != null)
return System.Convert.ToInt32(obj2);
return 0;
}
set { this.ViewState["Range1High"] = value; }
}
public int Range2Low
{
get
{
object obj2 = this.ViewState["Range2Low"];
if (obj2 != null)
return System.Convert.ToInt32(obj2);
return 0;
}
set { this.ViewState["Range2Low"] = value; }
}
public int Range2High
{
get
{
object obj2 = this.ViewState["Range2High"];
if (obj2 != null)
return System.Convert.ToInt32(obj2);
return 0;
}
set { this.ViewState["Range2High"] = value; }
}
}