I'm working on simple Android application. I'm using C# and Xamarin but i believe that programing language doesn't matter in that case since all changes are in .xml file.
Ok so my problem is related with preference that have dependency to other preference. First let me show my code then I will try to explain what i asking about.
<PreferenceCategory
android:title="#string/Pref_battery_settings"
android:key="pref_key_battery_settings">
<SwitchPreference
android:title="#string/Pref_battery_track_title"
android:summary="#string/Pref_battery_track_summary"
android:key="Pref_battery_track"
android:defaultValue="true"/>
<CheckBoxPreference
android:dependency="Pref_battery_track"
android:disableDependentsState="true"
android:title="#string/Pref_battery_track_battery_status_title"
android:summary="#string/Pref_battery_track_battery_status_summary"
android:key="Pref_battery_track_status"
android:defaultValue="false"/>
As You can see i have 2 preference. First Pref_battery_track is SwitchPreference that will determine is my app will track battery ( levels ect. ) If that preference will be setted to TRUE user will be able to use second preference which will decide if we want to track battery status or nor ( status is e.g Charging, Discharging ect.). In logical thinking if we set first preference to true we can decide do we want to track more information or not but right now i have problem. When i set Pref_battery_track to true then Pref_battery_track_status also to true and switch back first preference to false second will be still as true and we will be able to do code like :
var prefs = PreferenceManager.GetDefaultSharedPreferences(this);
var t = prefs.GetBoolean("Pref_battery_track_status", false);
This code will return true when Pref_battery_track_status will be true even when Pref_battery_track will be fasle. So my question is : Is there any way to set child preference to default value when parent preference is false ?
Hope you know what i asking about.
And yes i know that i can simply check before i use child preference like`
var prefs = PreferenceManager.GetDefaultSharedPreferences(this);
if(prefs.GetBoolean("Pref_battery_track", false))
{
var t = prefs.GetBoolean("Pref_battery_track_status", false);
// Do things
}`
But this solution is not nice since every time before i use child preference i will have to check parent.
You can subscribe the PreferenceChange event of your SwitchPreference, for example like this:
var switchp = PreferenceScreen.FindPreference("Pref_battery_track");
switchp.PreferenceChange += Switchp_PreferenceChange;
And then in Switchp_PreferenceChange set the Checked property of CheckBoxPreference for example:
private void Switchp_PreferenceChange(object sender, PreferenceChangeEventArgs e)
{
var isenabled = (bool)e.NewValue;
if (!isenabled)
{
var checkp = PreferenceScreen.FindPreference("Pref_battery_track_status") as CheckBoxPreference;
checkp.Checked = false;
}
}
Related
This question already has an answer here:
How to set a ToolStripMenuItem Visible in code?
(1 answer)
Closed 1 year ago.
I have encounter that issue a long time ago and again now. I cannot figure out what special thing had to be done to edit the ToolStripMenuItem control a Visible property while inside a form load.
in designer.cs
private System.Windows.Forms.ToolStripMenuItem mnuExport;
//
// mnuExport
//
this.mnuExport.Name = "mnuExport";
this.mnuExport.Size = new System.Drawing.Size(116, 22);
this.mnuExport.Text = "Export";
this.mnuExport.Visible = false;
this.mnuExport.Click += new System.EventHandler(this.mnuExport_Click);
in the form code
public partial class MainBuilder : Form
{
private void MainBuilder_Load(object sender, EventArgs e)
{
mnuExport.Visible = true;
}
}
In the code above export is a menu item of type ToolStripMenuItem which trough the property grid in the form design mode I have modified it's Visible property to false. So in the form load I want to switch to the visible state to true. I thought it be easy so I coded all the logic around and it failed. So I decided to remove all my code and simply hardcode the set to true and to my surprise this does not work.
When I put the breakpoint on the line in the form_load I clearly see it's false and if it let the line run the value is still false.
I recall seeing this issue in the past but cannot find anything about it. I also tried with 4-5 other menu item in that window and they all show the same behavior.
EDIT
just tried to put visible = true in the designer.cs instead and in the form_load still tells me the value is false. There is some major issues here.
As mentioned in the comments the property Visible getter does not reflect the actual inner property value until later in the lifecycle. It is still unavailable in the form_loaded event. My main problem is that one menu visibility state was based on if all sub menus are not visible then it should not either. To do so I was iterating on it's child and checking the Visible property. The problem is them having Visible to false due to the way it works the parent set it's own Visible to false as well.
I don't like the solution but that's the only way to make it work
// get all sub menus
var subMenus = mnuExport.DropDownItems.Cast<ToolStripItem>().ToList();
// create a list of bool that will store the visible state I want the controls to have. put them to true by default
var menusVisibleStates = Enumerable.Repeat(true, menus.Count).ToList();
// set the visibility state of each sub menus
for (int i = 0; i < menus.Count; i++)
{
// some logic is here that choose true or false but is irrelevant here
var visibleStateIWant = true;
// set the visible state stored
menusVisibleStates[i] = false;
// set the actual control value that will change later on
menus[i].Visible = false;
}
/// now here I use the state I have specified and NOT the menu object property
mnuExport.Visible = menusVisibleStates.Any(o => o);
I am attempting to check whether any variable has changed in a custom Editor Class, but I can't seem to get a result from the check. This is my custom editor class. I am using EditorGUI.BeginChangeCheck() & EditorGUI.EndChangeCheck():
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(TileManager))]
[CanEditMultipleObjects]
public class TileManagerEditor : Editor
{
public override void OnInspectorGUI()
{
TileManager tileManager = (TileManager)target;
EditorGUI.BeginChangeCheck();
serializedObject.Update();
tileManager.tileCount = (int)Mathf.Clamp(EditorGUILayout.IntField("Tile Count", tileManager.tileCount), 0, Mathf.Infinity);
tileManager.resizeTileCount = EditorGUILayout.Toggle("Resize Tile Count", tileManager.resizeTileCount);
tileManager.tileSize = EditorGUILayout.Vector3Field("Tile Size", tileManager.tileSize);
tileManager.tileSpacing = Mathf.Clamp(EditorGUILayout.FloatField("Tile Spacing", tileManager.tileSpacing), 0, Mathf.Infinity);
tileManager.relativeSpacing = EditorGUILayout.Toggle("Relative Spacing", tileManager.relativeSpacing);
if (tileManager.relativeSpacing == true)
{
tileManager.spacingMultiplier = Mathf.Clamp(EditorGUILayout.FloatField("Spacing Multiplier", tileManager.spacingMultiplier), 0, Mathf.Infinity);
}
EditorGUILayout.PropertyField(serializedObject.FindProperty("tilePrefab"), true);
EditorGUILayout.PropertyField(serializedObject.FindProperty("tileHolder"), true);
EditorGUILayout.PropertyField(serializedObject.FindProperty("tiles"), true);
serializedObject.ApplyModifiedProperties();
if (EditorGUI.EndChangeCheck())
{
tileManager.UpdateOnChange();
}
}
}
I have also tried Debug.Log(EditorGUI.EndChangeCheck()) instead of the if statement, but I don't get an output
There are two ways to track "something has changed" I can think off.
Both I would solve via a custom generic class changeTrackableValue<T> (a value where you can track changes). In both case you need a way to decide when all changes have become the "new normal".
Option 1 - Comparative
You keep a know "good" value. If the current and the know "good" value do not match, valueChanged would return true.
Properties:
if you take the long route back to the original value, it would read as "unchanged". usually adviseable for a Text Editor
It would basically double your memory demand, if not more then that (if parts are cut or added wholesale)
the original value does not need to be a property
Option 2 - the archive Bit
I copy that from the Filesystem. You use a property with a custom set for the value. You store one bool changed = false with each value. If the value is changed via set function, you set changed = true.
Properties:
minimal increase in memory useage
any change is tracked, even the ones back to the original state (can be good or bad)
you need a property with a public set and need to be able to modify said setter.
I can provide code for either one, if you need it.
I have not dealt with WinForms for a long time.
Now I'm stuck with something trivial but cannot figure it out.
I have a Winform and when a Timer Tick happens I want to show a message in a new form message box:
frmMessage frmM = new frmMessage();
frmM.txtMessage.Text = ConfigurationSettings.AppSettings["Message"];
frmM.Show();
It works but the text in the textbox shows as selected(with a blue background).
I tried
txtMessage.SelectionLength = 0;
Did not help.
Also tried to set focus to a different control, did not help either.
for now, as a workaround, I will use a Label.
This is a consequence of the way TextBox Class is implemented. If a selection is not specifically set, all text will be selected when the control gets focus.
From TextBox.OnGotFocus:
Protected override void OnGotFocus(EventArgs e) {
base.OnGotFocus(e);
If (!selectionSet) {
// We get one shot at selecting when we first get focus. If we don't
// do it, we still want to act Like the selection was set.
selectionSet = true;
// If the user didn't provide a selection, force one in.
If (SelectionLength == 0 && Control.MouseButtons == MouseButtons.None) {
SelectAll();
}
}
Additionally due to the way the SelectionLength Property is implemented, setting that property to zero does not set the selectionSet` flag as it is already zero.
Instead, set the TextBox.SelectionStart Property immediately after setting the text as this will set that flag.
txtMessage.SelectionStart = 0;
However, your work-a-round of using a Label to display a message is much more appropriate than using an input control.
This is not the best answer but it works. You can try this
frmMessage frmM = new frmMessage();
frmM.txtMessage.Text = "";
frmM.txtMessage.AppendText(ConfigurationSettings.AppSettings["Message"]);
frmM.Show();
I have a multiline textbox (tbxReminderText) in the following code that is not responding to my including tbxReminderText.Enabled = true;, even after trying to include it in multiple other locations. There is no difference whether or not I have the Enabled property set to true or false in the designer properties listing. Trying to refresh the controls, or anything else that I can think of trying, is not working. Here's the applicable code:
private void EditEntry_Load(object sender, EventArgs e) {
EntryType.Entries currentTypeEdited = new EntryType.Entries();
if (mainForm.alarmCLB.SelectedIndex != -1) {
currentTypeEdited = EntryType.Entries.Alarm;
} else if (mainForm.reminderCLB.SelectedIndex != -1) {
currentTypeEdited = EntryType.Entries.Reminder;
} else {
currentTypeEdited = EntryType.Entries.Timer;
//lets change the controls accordingly
//(no event handler to remove for the existing dtp
this.Controls.Remove(dtpActiveAt);
//change existing label
lblRingAt.Text = "Duration:";
//set up new control properties
/* MUCH dynamic insertion of controls removed here for brevity;
* -+=this is in part of the above if/else branch not used for the
* EntryType.Entries.Reminder, which is where my issue lies=+- */
this.Controls.Add(nudTmrHrs);
this.Controls.Add(lblTmrHours);
this.Controls.Add(nudTmrMin);
this.Controls.Add(lblTmrMinutes);
this.Controls.Add(nudTmrSec);
this.Controls.Add(lblTmrSeconds);
}
switch (currentTypeEdited) {
case EntryType.Entries.Alarm:
//edit our alarm entry heah
tbxReminderText.Text = "unavailable";
tbxReminderText.Enabled = false;
tbxName.Text =
HeadsUp.activeAlarms[mainForm.alarmCLB.SelectedIndex].Name;
dtpActiveAt.Value =
HeadsUp.activeAlarms[mainForm.alarmCLB.SelectedIndex].ActiveAt;
break;
case EntryType.Entries.Timer:
//edit timer heah
tbxReminderText.Text = "unavailable";
tbxReminderText.Enabled = false;
tbxName.Text =
HeadsUp.activeTimers[mainForm.timerCLB.SelectedIndex].Name;
//okay the following isn't a DTP, it's a 3 number field; we're
//going to have to handle this one differently, hopefully not with
//a completely different form
/*dtpActiveAt.Value =
HeadsUp.activeTimers[mainForm.timerCLB.SelectedIndex].remaining*/
break;
case EntryType.Entries.Reminder:
//reminder tiem
tbxReminderText.Text =
HeadsUp.activeReminders[mainForm.reminderCLB.SelectedIndex].Msg;
tbxReminderText.Enabled = true;
tbxName.Text =
HeadsUp.activeReminders[mainForm.reminderCLB.SelectedIndex].Name;
dtpActiveAt.Value =
HeadsUp.activeReminders[
mainForm.reminderCLB.SelectedIndex].ActiveAt;
break;
}
}
As annotated in the block commenting inline, the problem lies in the code branches selected in the if/else if/else statement activated when mainForm.reminderCLB.SelectedIndex != -1 (verified that it's taking this branch), and in the switch/case block active when currentTypeEdited = EntryType.Entries.Reminder.
I've googled and looked quite a bit on here, but I'm not finding anything similar. I'm guessing that I've made a stupid error somewhere, and I'm just not seeing it in code review... Can anybody help in pointing out the mistake that I made, a pointer to applicable resources (I've already looked at Controls.* on MSDN, etc), or let me know what other information I should include for better troubleshooting?
Any assistance is greatly appreciated.
Most likely the parent container has property Enabled set to false. When the parent container is not enabled children will not be enabled as well even if you try to set them to true.
Edit
try examining tbxReminderText.Parent.Enabled property value in the watch window and check its value before setting tbxReminderText.Enabled to true.
Sorry for the poor quality of the title. I couldn't think of a better way to phrase this.
For a project I'm currently working on with a few friends, I got myself in the situation where I have created a dynamic form (with reflection) which I now want to validate.
Example (ignore the black box, it contains old form elements which are now irrelevant and i didn't want to confuse you guys):
As you may have guessed already, it is an application for creating a mysql database.
Which is where I get to my problem(s). I want to disable checkboxes if others are checked.
For example: If I check "PrimaryKey" I want to disable the checkbox "Null".
Changing from unsigned to signed changes the numericupdown minimum and maximum etc.
But with reflection and all, I find it difficult to know exactly which checkbox to disable.
I was hoping you guys would have some suggestions.
I have been thinking about this for a while and a few thoughts have come to mind. Maybe these are better solutions than the current one.
Thought 1: I create UserControls for every datatype. Pro's: no problems with reflection and easy identifying of every control in the UserControl for validation. Con's: Copy-Pasting, Lots of UserControls, with a lot of the same controls.
Thought 2: Doing something with the description tags for every property of the classes. Creating rules in the description that allow me to link the checkboxes together. Here I'll only have to copy the rules to every class property and then it should be ok.
I had been thinking of other solutions but I failed to remember them.
I hope you guys can give me a few good pointers/suggestions.
[Edit]
Maybe my code can explain a bit more.
My code:
PropertyInfo[] properties = DataTypes.DataTypes.GetTypeFromString(modelElement.DataType.ToString()).GetType().GetProperties();
foreach (PropertyInfo prop in properties)
{
if (prop.Name != "Label" && prop.Name != "Project" && prop.Name != "Panel")
{
var value = prop.GetValue(modelElement.DataType, null);
if (value != null)
{
tableLayoutPanel1.Controls.Add(new Label { Text = prop.Name, Anchor = AnchorStyles.Left, AutoSize = true });
switch (value.GetType().ToString())
{
case "System.Int32":
NumericUpDown numericUpDown = new NumericUpDown();
numericUpDown.Text = value.ToString();
numericUpDown.Dock = DockStyle.None;
tableLayoutPanel1.Controls.Add(numericUpDown);
break;
case "System.Boolean":
CheckBox checkBox = new CheckBox();
checkBox.Dock = DockStyle.None;
// checkbox will become huge if not for these changes
checkBox.AutoSize = false;
checkBox.Size = new Size(16, 16);
if (value.Equals(true))
{
checkBox.CheckState = CheckState.Checked;
}
tableLayoutPanel1.Controls.Add(checkBox);
break;
default:
MessageBox.Show(#"The following type has not been implemented yet: " + value.GetType());
break;
}
}
}
}
Here is a mockup from my comments:
// The ViewModel is responsible for handling the actual visual layout of the form.
public class ViewModel {
// Fire this when your ViewModel changes
public event EventHandler WindowUpdated;
public Boolean IsIsNullCheckBoxVisible { get; private set; }
// This method would contain the actual logic for handling window changes.
public void CalculateFormLayout() {
Boolean someLogic = true;
// If the logic is true, set the isNullCheckbox to true
if (someLogic) {
IsIsNullCheckBoxVisible = true;
}
// Inform the UI to update
UpdateVisual();
}
// This fires the 'WindowUpdated' event.
public void UpdateVisual() {
if (WindowUpdated != null) {
WindowUpdated(this, new EventArgs());
}
}
}
public class TheUI : Form {
// Attach to the viewModel;
ViewModel myViewModel = new ViewModel();
CheckBox isNullCheckBox = new CheckBox();
public TheUI() {
this.myViewModel.WindowUpdated += myViewModel_WindowUpdated;
}
void myViewModel_WindowUpdated(object sender, EventArgs e) {
// Update the view here.
// Notie that all we do in the UI is to update the visual based on the
// results from the ViewModel;
this.isNullCheckBox.Visible = myViewModel.IsIsNullCheckBoxVisible;
}
}
The basic idea here is that you ensure that the UI does as little as possible. It's role should just be to update. Update what? That's for the ViewModel class to decide. We perform all of the updating logic in the ViewModel class, and then when the updating computations are done, we call the UpdateVisual() event, which tells the UI that it needs to represent itself. When the WindowUpdated Event occurs, the UI just responds by displaying the configuration set up by the ViewModel.
This may seem like a lot of work to set up initially, but once in place it will save you tons and tons of time down the road. Let me know if you have any questions.
Try relating the event of one checkbox to disable the other; something like this:
private void primaryKeyBox_AfterCheck(object sender, EventArgs e)
{
nullBox.Enabled = false;
}
This is a very simple example and would have to be changed a bit, but for what I think you're asking it should work. You would also have to add to an event for the boxes being unchecked. You would also need logic to only get data from certain checkboxes based on the ones that are and are not checked.
For all the other things, such as changing the numbers based on the dropdown, change them based on events as well.
For WinForms I would use data binding.
Create an object and implement INotifyPropertyChanged and work with that object.
Then, If you have an object instance aObj:
To bind the last name property to a textbox on the form do this:
Private WithEvents txtLastNameBinding As Binding
txtLastNameBinding = New Binding("Text", aObj, "LastName", True, DataSourceUpdateMode.OnValidation, "")
txtLastName.DataBindings.Add(txtLastNameBinding)
Take a look here for more info.
INotifyPropertyChanged