I need to redesign old windows forms application. So I decided to create a custom button control.
Let's say I defined a background color to be red for that custom button. When I do this:
place that button on the form
edit property of any other control
save the project
Visual Studio will automatically update the designer file and append:
this.btnCustom.BackColor = System.Drawing.Color.Red;
I don't want this to happen. This should be coded only in CustomButton class, not in the designer file. This will be the big problem if I decide to change button color to blue. Then, instead changing color only in CustomButton class, I would have to change color manually for each button. Is there any way to prevent this?
If your CustomControl code is something like this:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override Color BackColor
{
get
{
return Color.Red;
}
}
}
Then, when placed on Form, designer doesn't generate setter for BackgroundColor:
//
// userControl11
//
this.userControl11.Location = new System.Drawing.Point(67, 131);
this.userControl11.Name = "userControl11";
this.userControl11.Size = new System.Drawing.Size(154, 37);
this.userControl11.TabIndex = 2;
So if you change your CustomControl later, it gets changed everywhere used.
Related
In Visual Studio 2008, when I add some controls to form the designer creates some codes regarding the properties of the control automatically. Now, I'm using my own user controls and by adding them to the form, the designer again creates the code lines automatically, in this case the property FONT is one of those that I don't want the designer to add it since it overwrites the font setting in the upper level. Anyone knows how I can set which properties to be set in designer?
The designer only adds a line of code changing a property's value if it determines that the value is different from the DefaultValue[Attribute].
If your custom control wants to change what the default value of the Font property is (or any other base-class property), you have to perform a little wizardry:
public class MyControl : Control
{
public MyControl()
{
base.Font = new Font("Arial", 9.75f);
}
[DefaultValue(typeof(Font), "Arial, 9.75pt")]
public new Font Font
{
get { return base.Font; }
set { base.Font = value; }
}
}
Notice the 'new' keyword on the Font property? Font is not virtual, so you can't override it and we don't want to do that. You override to change behavior. We don't want to alter the behavior (which is why the code simply redirects back to the base), we just want to expose a new DefaultValue. This tricks the designer into considering the new default for your control.
We also make sure that our Font property has that value when it is constructed.
I have a MDI-Parent Form with many ChildForms, when I want to add a control on my Parent form, Child form appears under the control, For example I want to add a groupbox and a PictureBox on MDIParent Form, but when I call the Child Form it appears Under these controls.
frmChildForm1.TopMost=true doesn't works either.
I have attached a photo for more description.
What can I do?!
but I want to have an Image as Background
That's possible, you can set the BackgroundImage property of the MDI client control. The only obstacle is that you cannot directly get a reference to that control. You have to find it back by iterating the form's Controls collection. Like this:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
foreach (Control ctl in this.Controls) {
if (ctl is MdiClient) {
ctl.BackgroundImage = Properties.Resources.Lighthouse;
break;
}
}
}
}
Where Lighthouse was a sample image I added as a resource. Change it to use your own. Another common technique is to subscribe the Paint event for that control and draw whatever you want. A gradient is a common choice.
I have a usercontrol (UC1) that changes aspect at design time according to what the user wants to show.
A regular button that pops a window with usercontrol UC2 (the window is only shown at runtime)
The UC2 directly hosted in UC1 (the regular button is then not shown)
Since I want to use the same UC2 instance in both situation, I just transfer ownership between UC1 and the form.
public UC1 ()
{
_uc2 = new UC2 ();
}
public bool DisplayModeSimple
{
get { return _displayModeSimple; }
set
{
_displayModeSimple = value;
if (_displayModeSimple)
{
// ... Verify if _uc2 is already in Controls...
Controls.Remove (_uc2);
uiButton.Visible = true;
}
else
{
// ... Verify that _uc2 is not in Controls ...
Controls.Add (_uc2);
uiButton.Visible = false;
}
}
}
private void HandleButtonClick (object sender, EventArgs e)
{
// Not called if DisplayModeSimple=false since button is hidden...
using (var form = new PopupForm (_uc2))
{
form.ShowDialog (this);
}
}
Works fine in both design and runtime mode.
In design mode if I change the display mode UC1 behaves correctly.
However, controls that are on UC2 can be clicked like if it was runtime.
If I then close the form hosting UC1 and reopen it everything is back to normal, i.e., I cannot "click" on any controls in UC2.
The problem is that your first UserControl is hosted on VS, so it knows to be in design mode. The second UserControl is hosted in the first UserControl, so as its host is not a Designer, it thinks to be in a normal container and behaves accordingly. How to solve that is a bit tricky, as there isn't asimple solution AFAIK. Here you can find some workarounds. Another could be to test Site.DesignMode recursively, but it depends on the level of depth of your controls.
I'm trying to create an overlay in wpf (with darkening background), similar to the ones you can find on the web to popup images.
I would like it to be reusable in more than 1 part of the application, with diffent types of content.
this is the temporary code of the constructor of the adorner class (just to try)
private readonly Grid _grid = new Grid();
public DarkOverlayAdorner(UIElement adornedElement, Object content) :
base(adornedElement)
{
_grid.Background = new SolidColorBrush(Color.FromArgb(99, 0, 0, 0));
IsHitTestVisible = true;
var visual = content as UIElement;
if (visual != null)
_grid.Children.Add(visual);
}
In addition in the class (of course), I have the ovverrides of MeasureOverride and ArrangeOverride to give the adorner the correct size of the adorned element, GetVisualChild, and VisualChildCount...
The problem here is that the adorner is correctly shown, but no events or behaviour are applied on the adorned element. For example:
AdornerLayer layer = AdornerLayer.GetAdornerLayer(textBoxProva);
layer.Add(new DarkOverlayAdorner(textBoxProva, new Button{Content = "prova"}));
The button here is shown, but I can-t click the button and no effects on button mouseover are applied.
I still can't figure out the problem.
Ok, I've lost a lot of time trying to figure out what was the problem.
In the end I found the solution:
If you want the element added to react to events, I think that the element must be bound to the visual tree of the adorner.
The way to do it is to use a VisualCollection, intitialized to the adorner itself:
VisualCollection visualChildren;
FrameworkElement #object;
public DarkOverlayAdorner(UIElement adornedElement) :
base(adornedElement)
{
visualChildren = new VisualCollection(this);
#object = new Button {Content = "prova"};
visualChildren.Add(#object);
}
protected override Visual GetVisualChild(int index)
{
return visualChildren[index];
}
This way the events are correctly routed.
You might want to take a look at the ChildWindow control in the Extended WPF Toolkit. It is a control that pops up a Window with a modal background effect, and you can specify the content to put inside the Window.
I'm trying to write a text editor in WPF and I have a problem trying to locate the correct instance of an editor within a TabControl in response to a File -> Open action.
Tab items are added programatically and contain a WindowsFormsHost instance which in turn allows each tab to display an editor provided by the ScintillaNet WinForms component.
When a tab is selected and a user selects File -> Open, I need to locate the correct WindowsFormsHost instance based on the tab selection so I can load the file into the correct Scintilla instance.
Previously, I'd done this in WinForms simply by doing:
tabControl.TabPages[tabControl.SelectedIndex].Controls.Find("Scintilla")
How does this work in WPF?
To follow up regarding the solution I've gone with for now: I've decided to subclass the TabItem class and hold an additional property that references the WinForms ScintillaNet control:
public class CustomTabItem : TabItem
{
public Scintilla EditorControl
{
get; set;
}
}
And when I add new tabs, I just make sure that EditorControl is set to the new instance of Scintilla that is created too:
var editor = ScintillaFactory.Create();
var tab = new CustomTabItem()
{
Header = "Untitled",
Content = new WindowsFormsHost() { Name = "WinformsHost", Child = editor },
EditorControl = editor
};
tabControl.Items.Add(tab);
tab.Focus();
Now when an event is raised, I can query the selected tab and as cast to CustomTabItem in order to access the reference to the respective editor:
var editor = (tabControl.Items[tabControl.SelectedIndex] as CustomTabItem).EditorControl
editor.Text = "text here";
Hope that helps someone else.