I have a very annoying problem I'm trying to solve for couple of weeks. I have a WinForms C# project where I developed my custom control (ListView + ToolStrip with ToolStripButtons). This control is used in different forms inside solution - but in other projects. For different forms I need to make certain buttons visible or hidden, so I have added to my control corresponding properties like
public Boolean DeleteButtonVisible
{
get
{
return tsbDelete.Visible;
}
set
{
tsbDelete.Visible = value;
}
}
Some buttons are visible by default, some are hidden. In designer when editing a form with my control I'm able to change those properties, buttons on control become visible or hidden as they should. But every time I'm changing anything in my control source file in all forms those properties are reset to default values regardless of what I have set in designer and I have to restore those values manually. Well, I'm using a source control so this is not that hard, but performing "Undo" on a couple dozen of files every time I change a bit in another file is a damn disaster.
I have tried to use [DesignerSerializationVisibility] attribute to fix this issue. If I used it with value "Hidden" it didn't do any good at all - values were just not saved. "Content" made buttons randomly disappear even if by default they were visible. "Visible" lead to no effect, as this is default value...
I don't want to set every button visibility for every form in my code - this is just not the way it should be done.
Does anyone know something about this?
Yes, the Control.Visible property is special. The getter does not return the last assigned value, it only returns true when the control is actually visible. That can have side-effects, you've found one. In this case probably induced when the control switches out of design mode. To do this correctly, you must store the assigned state in a backing variable. Like this:
private bool tsbDeleteVisible;
public bool DeleteButtonVisible {
get { return tsbDeleteVisible; }
set { tsbDelete.Visible = tsbDeleteVisible = value; }
}
Be sure to initialize the default value of the backing variable to the default value of tsbDelete.Visible. Use the constructor to be sure.
Related
I had inherited the ComboBox winforms control.
In the first trial, I added some properties, and the designable ones showed Ok in the Property grid and all went OK.
Today, I added some others, and from that point, it makes the designer bombs.
Initially, the (presumably) offending property was "new DisplayMember" which referenced in the set and get methods the base.DisplayMember. Suspecting that was the mistake, I changed it to "public string DisplayProperty", to avoid name clash, but the error continued.
Ultimately, I also set a private variable displayProperty, and set the base.DisplayMember in the OnCreateControl event.
Nothing works.
Any help will be appreciated.
If it´s required, I could put the code, but it´s very big.
TIA
EDIT: looking at the Application events, they show the VS failures, but don´t tells anything regarding the error.
I had a property that looked like
bool autoComplete = true;
[Category("Autocomplete")]
[Description("This is the only property of this group to set. All others will be set accordingly.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public bool AutoComplete
{
get { return AutoComplete; }
set { autoComplete = value; }
}
See the capital A in the get procedure... once in the designer, recursive calls ended in a stack overflow. But none of this were explicit in the event log.
Hours chasing a phantom.
In my code behind I have two method to enable or disable a group of controls depending upon the value of a field on a form. One of these methods works as expected, and the other doesn't ... quite. The one that works depends upon the value of a Checkbox, while the other depends upon the value of a drop-down list (I believe that this difference is irrelevant - I mention it only for completeness). I've simplified these methods for readability, but the only significant difference from the production system is that they set a number of controls, not just one.
private void SetControlsFromDropDown(int statusID)
{
// This method doesn't work
bool enable = (statusID == (int)ReqStatus.CompletedOK)
this.myTextBox.Enabled = enable;
}
private void SetControlsFromCheckBox(bool enable)
{
// This method works
cboMyDropDown.Enabled = enable;
}
Where the first method fails is that it sets the controls correctly when the form is loaded. However, when the drop-down list changes, the method is called and the value of the bool variable "enable" is correctly set, and the code runs through as expected (and a watch on the Enabled property of the controls that are being set shows that they are toggled as expected) - BUT BUT BUT the controls remain firmly unchanged in the interface. So, if they were initially set to Enabled = false they remain disabled even though the method might have set them to Enabled = true.
What is causing me conniptions is that if I put setting of this.myTextoxBox into the second method, it toggles correctly.
I get the impression I haven't explained myself very clearly. In essence, two more-or-less identical methods, called from similar events, operating in arguably indistinguishable ways, behave differently in real-time. One will toggle the Enabled property of a group of controls ad lib., while the other will toggle it once, never to be toggled again.
Any thoughts gratefully received.
Edward
The problem was caused by a failure of the brain. I was getting an incorrect value from the drop-down list. Apologies for any time wasted.
I'm not really sure about this, but try to remove the 'this'
Just put the following:
myTextBox.Enabled = enable;
I have a combobox embedded in a toolstrip - a ToolStripCombobox instance.
The list of items is the list of values of an enum.
I'd like to be able to load/save the selection (One of the Selected[Index|Item|Text|...] properties, from/to the app's Settings "mechanism".
Ideally, I'd like to be able to do that from the designer.
Normally, hooking a control's property to a certain setting is done (in the designer) from the control's properties, under (ApplicationSettings) - but none of the SelectedXXX properties shows up in there.
FWIW, in the particular case of toostrip-bound combo-boxes, the actual SelectedXXX properties are actually found a bit deeper, at toolStripComboInstance.ComboBox.SelectedXXX.
What I have done so far is configure the binding in code:
m_runTypeCombo //the toolstrip control
.ComboBox //the actual combobox
.DataBindings.Add(
new System.Windows.Forms.Binding(
"SelectedItem",
global::JavaPad.Properties.Settings.Default,
"RunType",
true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged
)
);
The above works, but I was hoping for something cleaner (i.e. designer-based). If the built-in ToolStripCombobox doesn't support this, is there a (simple) way to derive my own type from that, and expose the SelectedXXX properties in such a way that it works with the Application Settings infrastructure (and its support in the designer)?
If you are willing to wrap the TooltipComboBox in your own custom control, you can do it like this:
public class MyCombo : ToolStripComboBox
{
[SettingsBindable(true)]
public int SelectedIndex
{
get { return ComboBox.SelectedIndex; }
set { ComboBox.SelectedIndex = value; }
}
}
Note that I haven't tested this beyond confirming that I can add the control to the ToolStrip, and that I can select a property - You may need to add PropertyChanged Events to make it work fully.
I need to find a way to determine if the Visible property of a control is set via a property change or if is inheriting it value from its parent. Using the Reflector, I find that the functions this.GetVisibleCore() and this.GetState() are both internal methods so I cannot call them.
The widgets themselves are created dynamically so I do not want to attach a method to the VisibleChanged event just after the creation of each widget so can try to monitor this property. If I have to, I guess I will but I am looking for something just a bit more elegant.
Edit
What I really want to know is when I hide the form and go to close it or build the form but keep it hidden, what Visible values are false because the form is hidden and what values are false because they were set to false. Again I do not want to have to attach a method to each VisibleChanged event of each widget. I just want to somehow read it off the Control object.
It's still not very clear, but I assume that the problem is that the Visible property getter returns the actual visibility state of the control. Which is not just the last assigned value to Visible, it also takes account of whether the parents of the control are visible. In other words, if you've got a button in a UserControl and the UserControl's Visible = false then the button's Visible will always be false as well.
You can override SetVisibleCore() to find out if the control intends to be visible:
public bool CouldBeVisible { get; set; }
protected override void SetVisibleCore(bool value) {
CouldBeVisible = value;
base.SetVisibleCore(value);
}
I have a user control panel that has two buttons on it. Other user controls inherit from this control and set a property to true if the buttons should be visible. Everything runs how I want it to but what I'm looking for is a way to clear these buttons from the designer window for forms where this property is left at false.
looks like:
[DefaultValue(false)]
public bool ShowButtons{
set
{
mShowButtons = value;
UpdateButtons();
}
get
{
return mShowButtons;
}
}
This property shows in the properties window and the buttons are always shown in the designer window. Is there some way to have the designer evaluate this when the property is changed to get the buttons to clear from the inheriting form? I was unable find a designer attribute to do this.
Try adding a get:
bool mShowButtons;
[DefaultValue(false)]
public bool ShowButtons
{
get
{
return mShowButtons;
}
set
{
mShowButtons = value;
UpdateButtons();
}
}
Now when editing your derived class in the Designer, you should be able to see a ShowButtons property in properties window when the derived UserControl is selected. (It will be in the "Misc" section unless you add the appropriate attribute). If you set it there, it should have the appropriate affect in the Designer (Assuming the contents of the UpdateButtons() function work correctly)).
A property must be public and have bot get and set in order to display in the Properties editor window. Once it is, then setting the value in the properties window will "save" that setting for the designed control in the control's resources/implementation.
I use this functionality quite often to specialize derived UserControls, so I know it should work for you (although there may be other issues at play).