I have a custom control that I added an Id string property to.
When the control is placed on a form, I want the constructor to set this to Guid.NewGuid().ToString(), but only if it hasn't been set before.
When I manually edit this property from the designer, it adds a line of code to the Designer.cs file. How can I do that programmatically?
Specifically, how to do it from within the custom control?
I have created sample usercontrol that fits your requrements. In this case is "MyLabel" that inherits from Label.
First create separate library that holds MyLabel class and here is the code for this class:
public class MyLabel: Label
{
public string ID { get; set; }
protected override void OnCreateControl()
{
base.OnCreateControl();
if (this.DesignMode && string.IsNullOrEmpty(this.ID))
{
this.ID = Guid.NewGuid().ToString();
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
this.Text = this.ID;
}
}
As you see my control has ID property that is populated if control is in design mode and no value has been set yet. Checking design mode is important so value will not change if you reopen the project.
Override for OnPaint event is there just to see actual ID value in real time it's not required.
I believe what you need is Properties.Settings. See MSDN page.
You can set these to default values during design, or load and save at runtime.
Example: with the designer, create a new user scoped string[] named IDs. Then in your constructor, something like this
string ID = "";
if (Properties.Settings.Default.IDs!=null && Properties.Settings.Default.IDs.Length>0) {
ID = Properties.Settings.Default.IDs[0];
}
else {
ID = "random";
Properties.Settings.Default.IDs = new string[1];
Properties.Settings.Default.IDs[0] = ID;
Properties.Settings.Default.Save();
}
This will use the first element of the stored array if there is one, or it will create a new string if there isn't, and persist it (so it will be read from the settings next time you run the program).
Related
I'm trying to create a custom BindingNavigator control in with some extra ToolStripButton (Edit and ExportToExcel).
The ToolStripButton is added to the BindingNavigator, but I cannot select this new ToolStripButton, e.g., to add code in its Click event handler. Actually, the ToolStripButtons appear locked.
Here is my code and an image that should describe the problem:
using System.Windows.Forms;
public class BindingNavigator : System.Windows.Forms.BindingNavigator
{
public ToolStripButton btnEdit;
public ToolStripButton btnExcelExport;
public BindingNavigator()
{
this.LayoutCompleted += BindingNavigator_LayoutCompleted;
}
public void BindingNavigator_LayoutCompleted(object sender, System.EventArgs e)
{
if (this.Items.Contains(btnEdit))
return;
if (this.Items.Count >= 11)
{
btnEdit = new ToolStripButton();
btnEdit.Image = global::BaseControls.Properties.Resources.Edit___16x16;
btnEdit.Name = "btnEdit";
this.Items.Insert(10, btnEdit);
this.Items.Add(new ToolStripSeparator());
btnExcelExport = new ToolStripButton();
btnExcelExport.Image = global::BaseControls.Properties.Resources.Excel___16x16;
btnExcelExport.Name = "btnExcelExport";
this.Items.Insert(13, btnExcelExport);
}
}
}
The BindingNavigator class has a dedicated Designer, BindingNavigatorDesigner, derived from ToolStripDesigner.
The Designer calls the public virtual AddStandardItems() method, which is then called by Form Designer when a BindingNavigator is added to a Form.
To make your Buttons functional, override this method in a custom class and add new buttons here.
Now your ToolStripButtons are serialized in the Form Designer and, if you double-click one of your custom buttons, a Click handler is added to the Form.
Notes you can find in the .Net Source Code:
Override this method in derived classes to define additional or
alternative standard items. To ensure optimal design-time support
for your derived class, make sure each item has a meaningful value in
its Name property. At design time, this will be used to generate a
unique name for the corresponding member variable. The item's Name
property will then be updated to match the name given to the member
variable.
As you can see, now the buttons are fully functional
I suggest you modify your custom BindingNavigator like this:
▶ Don't name your Custom Control BindingNavigator
public class BindingNavigatorEx : BindingNavigator
{
private ToolStripItem btnEdit;
private ToolStripItem btnExcelExport;
public BindingNavigatorEx() { }
public override void AddStandardItems()
{
base.AddStandardItems();
Items.Add(new ToolStripSeparator());
btnEdit = new ToolStripButton() {
Image = Properties.Resources.Edit___16x16,
Name = "bindingNavigatorButtonEdit",
DisplayStyle = ToolStripItemDisplayStyle.Image
};
Items.Add(btnEdit);
btnExcelExport = new ToolStripButton() {
Image = Properties.Resources.Excel___16x16,
Name = "bindingNavigatorButtonExcelExport",
DisplayStyle = ToolStripItemDisplayStyle.Image
};
Items.Add(btnExcelExport);
}
}
I am trying to develop a program in which it could create forms and add controls to it at runtime.
It also should be able to save, (Open and Edit) the forms created with the new controls added it at Runtime.The Application starts In the Main form.
CODE BEHIND MAIN Form
private void Btn_CREATE_FORM_Click(object sender, EventArgs e)
{
Form_Properties fp = new Form_Properties();
fp.Show();
}
private void BTn_ADD_BTN_Click(object sender, EventArgs e)
{
/// WHAT CODE SHOULD I ENTER TO ADD BUTON TO NEW FORM
}
Basically the main form is used to create/open/save new forms and add controls to it.
When the user clicks on Create New Form button the user will be presented with the following form (FORM_PROPERTIES) in which the user can customize the name, width and height of the new form.
CODE BEHIND FORM_PROPERTIES Form
public partial class Form_Properties : Form
{
public Form_Properties()
{
InitializeComponent();
}
String form_name;
int form_width;
int form_height;
private void Btn_OK_Click(object sender, EventArgs e)
{
form_name = TBox_NAME.Text;
form_width = Convert.ToInt32(TBox_WIDTH.Text);
form_height = Convert.ToInt32(TBox_HEIGHT.Text);
New_Form nf = new New_Form();
nf.Text = form_name;
nf.Width = form_width;
nf.Height = form_height;
nf.Show();
}
}
The following image shows what happens at runtime based on the code I have written so far.
ISSUES
Need help to Write Code
To add controls to new form created.
To Save/Open/Edit Functionalities.
I also need to know the method to access properties of added controls at runtime.
eg: If the user adds a text box to the NEW FORM and decides to type some text in it, I need a method to save that text.
Is there a way for me to name the added controls?
It seems you want to build some kind of WinForms' form designer. Your program would be similar to Glade (though Glade is much more powerful).
I'm afraid the question is too broad, though. There are many questions to answer, for example, how do you describe the created interface.
While Glade uses XML, you can choose another format, such as JSON. Let's say that you have a TextBox with the word "example" inside it.
{ type:"textbox" text:"example" }
It seems you want to add your components to the form as in a stack. Maybe you could add its position. For example, a form containing a label
("data"), a textbox ("example"), and a button ("ok"), would be:
{
{ pos:0, type:"label", text:"data" },
{ pos:1, type:"textbox", text:"example" },
{ pos:2, type:"button", text:"ok" },
}
But this is just a representation. You need to a) store this when the form is saved, and b) load it back when the form is loaded.
For that, you will need a class representing the components, such as:
public class Component {
public override string ToString()
{
return string.Format( "position:{0}, text:{1}", this.Position, this.Text );
}
public int Position { get; set; }
public string Text { get; set; }
}
public class TextBoxComponent: Component {
public override string ToString()
{
return base.ToString() + "type:\"textbox\"";
}
}
...and so on. This is a big task, I'm afraid, with no simple answer.
I created simple user control consisting of 3 elements:
2 radio buttons and table layout panel aka Yes or No control.
I created custom property boolean "Value" which changes depending of checked radio button.
UPDATE 1: I added that control to form and bind property "Value" to settings and in control code I added logic to determine which radio but should be checked but after saving settings and reloading form neither of radio buttons are checked.
How can I achieve that effect with the least effort.
Below the code:
public partial class YesOrNoControl : UserControl
{
public YesOrNoControl()
{
InitializeComponent();
LoadValue();
}
[Description("Sets the value of Control"), Category("Behavior"), DefaultValue(false), Browsable(true)]
public bool Value { get; set; }
void LoadValue()
{
if (Value)
{
YesButton.Checked = true;
}
else
{
NoButton.Checked = true;
}
}
private void YesButton_Click(object sender, EventArgs e)
{
Value = true;
}
private void NoButton_Click(object sender, EventArgs e)
{
Value = false;
}
}
You can define application settings within the IDE (under project settings).
You can then manipulate the settings by use of the Properties.Settings namespace.
Settings are automatically loaded at runtime, you can save the settings by calling the Save() method.
More links: Using Application Settings and User Settings
Applications Settings for WinForms
I managed to solve my problem.
I modified property "Value" to get value from application setting (specially created for this purpose) and set value to same application setting.
At the end of setter I added saving of application settings.
It solves the main problem but it's kind of workaround, not the true answer to problem.
Below the modified code of property:
public bool Value
{
get
{
return Properties.Settings.Default.YesOrNoControlValue;
}
set
{
Properties.Settings.Default["YesOrNoControlValue"] = value;
Properties.Settings.Default.Save();
}
}
I have created a simple C# Windows 8 grid application.
If you're unfamiliar with this layout, there is a brief explanation of it here :
Link
What I would like to have is simple - some custom ItemDetailPages. I'd like to be able to click on some items on the GroupDetailPage and the GroupedItemsPage and navigate to a custom .xaml file, one where I can include more than one image.
I'm sure there is a simple way of doing that that I have missed out on, and I'm also sure that this information will be useful for a lot of people, so I will be offering a bounty on this question.
I have struggled with doing this so far :
I've created a CustomDataItem in the SampleDataSource.cs class :
/// <summary>
/// Generic item data model.
/// </summary>
public class CustomDataItem : SampleDataCommon
{
public CustomDataItem(String uniqueId, String title, String subtitle, String imagePath, String description, String content, SampleDataGroup group)
: base(uniqueId, title, subtitle, imagePath, description)
{
this._content = content;
this._group = group;
}
private string _content = string.Empty;
public string Content
{
get { return this._content; }
set { this.SetProperty(ref this._content, value); }
}
private SampleDataGroup _group;
public SampleDataGroup Group
{
get { return this._group; }
set { this.SetProperty(ref this._group, value); }
}
}
However, obviously, adding to the ObservableCollection
private ObservableCollection<SampleDataGroup> _allGroups = new ObservableCollection<SampleDataGroup>();
public ObservableCollection<SampleDataGroup> AllGroups
{
get { return this._allGroups; }
}
is impossible with a different data type. So what can I do in this case ?
Thanks a lot.
I have a simple grid application; how do I make it possible to have one of the elements in the group item page link to a custom item detail page ?
Ok, lets take the app that is generated when using the "Grid App" template from Visual Studio.
The data class for the elements on the group items page is the SampleDataItem class. What you can do is add some type of data field (bool, int, or other) that indicates how to handle the navigation. In this example, we are keeping it simple, so we add a bool to indicate whether the navigation is custom or not.
public class SampleDataItem : SampleDataCommon
{
// add flag as last param
public SampleDataItem(String uniqueId, String title, String subtitle,
String imagePath, String description, String content, SampleDataGroup group,
bool isCustomNav = false)
: base(uniqueId, title, subtitle, imagePath, description)
{
this._content = content;
this._group = group;
this.IsCustomNav = isCustomNav;
}
// to keep it simple this doesn't handle INotifyPropertyChange,
// as does the rest of the properties in this class.
public bool IsCustomNav { get; set; }
...
}
So when you are adding a new SampleDataItem object to be displayed, you just need to set the isCustomNav field in the constructor.
Now all we have to do is change the already existing click event handler in the grid on the grouped item page (GroupedItemsPage.xaml.cs):
void ItemView_ItemClick(object sender, ItemClickEventArgs e)
{
// Navigate to the appropriate destination page, configuring the new page
// by passing required information as a navigation parameter
var item = (SampleDataItem)e.ClickedItem;
var itemId = item.UniqueId;
if (item.IsCustomNav == false)
{
// default
this.Frame.Navigate(typeof(ItemDetailPage), itemId);
}
else
{
// custom page
this.Frame.Navigate(typeof(ItemDetailPage2), itemId);
}
}
All we are doing above is getting the selected item and then testing the navigation flag that we added earlier. Based on this we navigate to either the original ItemDetailPage or a new one called ItemDetailPage2. As I mentioned before, the navigation flag doesn't have to be a bool. It can be an int or enum or some other type that tells us where to navigate.
Note that if you want similar behavior on the GroupDetailsPage, you just have to update the click event handler there the same way.
Hope that helps.
Yes you should be able to create a custom or different data type. If you create a Win8 app using the grid template, you see that the template does three things for you:
1) It creates three types, SampleDataCommon, which is the base, SampleDataItem, which implements SampleDataCommon and adds two new properties - content and group, and SampleDataGroup which also implements SampleDataCommon, adds a method, ItemsCollectionChanged, and adds two properties, Items and TopItems.
2) It creates a class called SampleDataSource, in which a collection of SampleDataGroup is created and named AllGroups: ObservableCollection AllGroups.
3) It binds Items and AllGroups of SampleDataSource to objects in XMAL pages.
In your case, you use the same data structure. In other words, you will create a group with items, etc.
I am working on an ASP .net project. I am trying to load a user control in a Control object with the following code and i am trying to pass a parameter to that control. On the debugging mode I get an error on that line saying that The file '/mainScreen.ascx?matchID=2' does not exist.. If I remove the parameters then it works ok. Can anyone help me to pass those parameters? Any suggestions?
Control CurrentControl = Page.LoadControl("mainScreen.ascx?matchID=2");
You cannot pass the parameter via query-string notation because user controls are simply "a building blocks" referenced by virtual path.
What you can do instead is to make a public property and assign the value to it once the control is loaded:
public class mainScreen: UserControl
{
public int matchID { get; set; }
}
// ...
mainScreen CurrentControl = (mainScreen)Page.LoadControl("mainScreen.ascx");
CurrentControl.matchID = 2;
You can now use the matchID inside your user control like the following:
private void Page_Load(object sender, EventArgs e)
{
int id = this.matchID;
// Load control data
}
Note that the the control is participating in the page life cycle only if it's added into the page tree:
Page.Controls.Add(CurrentControl); // Now the "Page_Load" method will be called
Hope this helps.