I made a simple user control for a tab, however when I call it it shows up very small and can resize it to any size at all, here is the code. What do I wrong?
public class tabController : UserControl
{
public tabController(string id)
{
InitializeComponent(id);
}
public void InitializeComponent(string id)
{
TabControl tabControl;
TabPage tab1, tab2, tab3, tab4, tab5, tab6, tab7, tab8, tab9, tab10;
tabControl = new TabControl();
tabControl.Location = new Point(500, 250);
tabControl.Size = new Size(500, 500);
tabControl.ClientSize = new Size(500, 500);
var xmlData = Binder.fSelect.GetData(3, 1, 1, 0, "", "", 0, 25);
StringReader sr = new StringReader(xmlData);
//dsData.ReadXml(xmlData);
//string xmlString = sw.ToString();
DataSet ds = new DataSet();
ds.ReadXml(sr);
int i = 0;
for (i = 0; i <= ds.Tables[0].Rows.Count - 1; i++)
{
//string v = ds.Tables[0].Rows[i].ItemArray[2].ToString();
if ((ds.Tables[0].Rows[i].ItemArray[4].ToString()) == "114")
{
if (i == 0)
{
tab1 = new TabPage(ds.Tables[0].Rows[i].ItemArray[1].ToString());
tabControl.TabPages.Add(tab1);
}
}
}
tabControl.Dock = DockStyle.Fill;
this.Controls.Add(tabControl);
Hie
Try using the Dockstyle property of the user control to Dockstyle.Fill when you call it.
Related
I just read and applied it to the dynamic object on the panel for the container, the label for the title, the textbox for the contents.
but here I can't save it when I fill in the data in the textbox.
this is my deserialize xml code:
string Location= Path.Combine("D:\\Data\\Code.xml");
XmlDocument doc = new XmlDocument();
doc.Load(lokasiString);
foreach (XmlNode node in doc.DocumentElement)
{
string name = node.Attributes[0].InnerXml;
string value = node.InnerText;
// create panel
Panel panel = new Panel();
panel.Name = "panelImages";
panel.Size = new Size((int)(this.Width*0.9), 30);
panel.Dock = DockStyle.Top;
panel.BorderStyle = BorderStyle.FixedSingle;
Label l = new Label();
l.Text = name;
l.Font = new Font("Serif", 12, FontStyle.Bold);
l.ForeColor = Color.Black;
l.Size = new Size((int)(this.Width * 0.2), 30);
l.Dock = DockStyle.Left;
TextBox tb = new TextBox();
tb.Text = value;
tb.Font = new Font("Serif", 12, FontStyle.Bold);
tb.ForeColor = Color.Black;
tb.Size = new Size((int)(this.Width * 0.9), 30);
tb.Dock = DockStyle.Left;
panel.Controls.Add(tb);
panel.Controls.Add(lt);
panel.Controls.Add(l);
flowLayoutPanel1.Controls.Add(panel);
}
and this my Xml Code:
<resources>
<string name="name">Tap Crush</string>
<string name="mode">Slow</string>
<string name="score">12345</string>
</resources>
I have no prior knowledge of parsing Xml with C#.
Define model classes and use databinding to edit the model, then you can break the problem to the following pieces:
Defining a Model class containing a List<Resource> and each Resource having Title and Content.
Write some logic to load model from xml or save model to xml.
Write a piece of code to arrange UI and setup UI controls to use databinding to your mode.
Then you can easily Load data from xml, edit in the UI and Save data to xml.
Model classes
You can model classes like this:
public class Model
{
public List<Resource> Resources { get; set; }
}
public class Resource
{
public string Title { get; set; }
public string Content { get; set; }
}
Setting up UI
There are different approaches to dynamically show a collection of controls in a form. Here I'll show how you can do that using a DataGridView as well as a TableLayoutPanel:
DataGridView
TableLayoutPanel
Create DataGridView
var dg = new DataGridView();
dg.Dock = DockStyle.Fill;
dg.BorderStyle = BorderStyle.None;
dg.GridColor = Color.Black;
dg.AutoGenerateColumns = true;
dg.EditMode = DataGridViewEditMode.EditOnEnter;
dg.DataSource = model.Resources;
dg.DataBindingComplete += (o, a) =>
{
dg.RowHeadersVisible = dg.ColumnHeadersVisible = false;
dg.AllowUserToResizeColumns = false;
dg.AllowUserToResizeRows = false;
dg.BackgroundColor = SystemColors.Control;
dg.Columns[0].ReadOnly = true;
dg.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
dg.Columns[0].DefaultCellStyle.ForeColor = Color.Black;
dg.Columns[0].DefaultCellStyle.BackColor = SystemColors.Control;
dg.Columns[0].DefaultCellStyle.SelectionForeColor = Color.Black;
dg.Columns[0].DefaultCellStyle.SelectionBackColor = SystemColors.Control;
dg.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
};
this.Controls.Add(dg);
Create TableLayoutPanel
var tlp = new TableLayoutPanel() { ColumnCount = 2, AutoSize = true };
tlp.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
tlp.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
tlp.SuspendLayout();
foreach (var resource in model.Resources)
{
tlp.RowStyles.Add(new RowStyle(SizeType.AutoSize));
var lbl = new Label() { AutoSize = true, Margin = new Padding(4) };
lbl.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
lbl.DataBindings.Add(new Binding(nameof(Label.Text), resource, nameof(Resource.Title)));
var txt = new TextBox();
txt.DataBindings.Add(new Binding(nameof(TextBox.Text), resource, nameof(Resource.Content)));
txt.Dock = DockStyle.Fill;
tlp.Controls.AddRange(new Control[] { lbl, txt });
}
tlp.ResumeLayout();
this.Controls.Add(tlp);
Load and Save Model
You can create a class like this:
public class ModelFactory
{
public Model FromXmlString(string xml)
{
return new Model()
{
Resources = XElement.Parse(xml).Elements()
.Select(x => ResourceFromXElement(x)).ToList()
};
}
public string ToXmlString(Model model)
{
return new XElement("resources",
model.Resources.Select(x => ResourceToXElement(x)).ToArray())
.ToString();
}
private Resource ResourceFromXElement(XElement element)
{
return new Resource()
{
Title = element.Attribute("name").Value,
Content = element.Value
};
}
private XElement ResourceToXElement(Resource resource)
{
return new XElement("string",
new XAttribute("name", resource.Title),
resource.Content);
}
}
Then easily load and save model:
Model model;
ModelFactory modelFactory = new ModelFactory();
private void loadButton_Click(object sender, EventArgs e)
{
var xml = #"
<resources>
<string name=""name"">Tap Crush</string>
<string name=""mode"">Slow</string>
<string name=""score"">12345</string>
</resources>";
//Load model from xml
model = modelFactory.FromXmlString(xml);
//Setup UI
}
private void saveButton_Click(object sender, EventArgs e)
{
//Save model to xml
var xml = modelFactory.ToXmlString(model);
MessageBox.Show(xml);
}
I want to add some panel dynamically into a single panel on a button click. And each dynamic panel consist of multiple text box in horizontally. And then I want to save those text box value into the database.
I have completed to add dynamic panel and horizontal multiple text box into that panel. But couldn't know how to save them into database.
Here is the code I have written:
int v = 0;
TextBox txt1;
TextBox txt2;
TextBox txt3;
TextBox txt4;
TextBox txt5;
ComboBox cmb4;
public void tett()
{
v = 0;
Panel whitePanel = new Panel();
whitePanel.Name = "wt";
// Quantity
txt1 = new TextBox();
txt1.Location = new Point(192, 38);
txt1.Size = new Size(120, 24);
txt1.Name = "text" + v ;
txt1.Text = txt1.Name;
v = v + 1;
// Total Price
txt2 = new TextBox();
txt2.Location = new Point(566, 38);
txt2.Size = new Size(120, 24);
txt2.Name = "text" + v;
txt2.Text = txt2.Name;
txt2.TextChanged += Txt2_TextChanged;
v = v + 1;
// Unit Price
txt3 = new TextBox();
txt3.Location = new Point(753, 38);
txt3.Size = new Size(120, 24);
txt3.Name = "text" + v;
txt3.Text = txt3.Name;
v = v + 1;
// Sell Price
txt4 = new TextBox();
txt4.Location = new Point(903, 38);
txt4.Size = new Size(120, 24);
txt4.Name = "text" + v;
txt4.Text = txt4.Name;
v = v + 1;
// Product
txt5 = new TextBox();
txt5.Location = new Point(5, 38);
txt5.Size = new Size(120, 24);
txt5.Name = "text" + v;
txt5.Text = txt5.Name;
txt5.AutoCompleteSource = AutoCompleteSource.CustomSource;
txt5.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
txt5.MouseClick += textBox5_MouseClick;
Label lbl3 = new Label();
Label lbl4 = new Label();
Label lbl5 = new Label();
Label lbl6 = new Label();
Label lbl7 = new Label();
Label lbl8 = new Label();
lbl3.Location = new Point(5, 15);
lbl3.Text = "Product";
lbl4.Location = new Point(192, 15);
lbl4.Text = "Quantity";
lbl5.Location = new Point(379, 15);
lbl5.Text = "Unit";
lbl6.Location = new Point(566, 15);
lbl6.Text = "Total Price";
lbl7.Location = new Point(753, 15);
lbl7.Text = "Unit Purchase Price";
lbl8.Location = new Point(903, 15);
lbl8.Text = "Unit Sell Price";
cmb4 = new ComboBox();
// Unit
cmb4.Location = new Point(379, 38);
cmb4.Size = new Size(120, 24);
whitePanel.BackColor = ColorTranslator.FromHtml("#ECF0F5");
whitePanel.Location = new Point(1, a * 10);
whitePanel.Size = new Size(1330, 60);
var _button = new Button();
_button.Text = "Dispose";
_button.Name = "DisposeButton";
_button.Location = new Point(1053, 38);
_button.MouseClick += _button_MouseClick;
whitePanel.Controls.Add(_button);
a = a + 5;
v = v + 1;
whitePanel.Controls.Add(lbl3);
whitePanel.Controls.Add(lbl4);
whitePanel.Controls.Add(lbl5);
whitePanel.Controls.Add(lbl6);
whitePanel.Controls.Add(lbl7);
whitePanel.Controls.Add(lbl8);
whitePanel.Controls.Add(txt1);
whitePanel.Controls.Add(txt2);
whitePanel.Controls.Add(txt3);
whitePanel.Controls.Add(txt4);
whitePanel.Controls.Add(txt5);
whitePanel.Controls.Add(cmb4);
panel1.Controls.Add(whitePanel);
}
In this way the output is like this..... By click on the New Purchase this multiple panel with text box will appear:
Multiple dynamic panel with multiple text box
Here the way of setting text box name is not seems better way to me. I want to use an array for set the name of text boxes.
And after all I want to save those values into db by click on the save button using an array or for loop... But I don't know how to define it..
Can anyone please help me?
And thanks in advance
With this approach, a gridview is usefull.
But within your question, the approach is;
int rowNum = 1;
public void tett() {
Control[] controlsToAdd = { new TextBox(), new TextBox(), new ComboBox(), new TextBox(), new TextBox(), new TextBox(), new Button() };
string[] labels = { "Product", "Quantity", "Unit", "Total Price", "Unit Purchase", "Unit Sell Price" };
Panel whitePanel = new Panel() {
Name = "wt",
Dock = DockStyle.Top,
AutoSizeMode = AutoSizeMode.GrowAndShrink,
AutoSize = true,
Padding = new Padding(0, 5, 0, 5),
BackColor = ColorTranslator.FromHtml("#ECF0F5")
};
int controlX = 5, controlY = 15, controlDistance = 15;
for (int i = 0; i < controlsToAdd.Length; i++) {
if (labels.Length > i) {
var label = new Label() {
Text = labels[i],
Location = new Point(controlX, controlY)
};
whitePanel.Controls.Add(label);
}
var control = controlsToAdd[i];
control.Location = new Point(controlX, controlY + 23);
control.Size = new Size(120, 24);
if (control is Button) {
control.Name = "disposeButton" + i;
control.Text = "Dispose";
control.Click += _button_MouseClick;
} else {
if(i == 0) { //if it is the Product textbox
((TextBox)control).AutoCompleteSource = AutoCompleteSource.CustomSource;
((TextBox)control).AutoCompleteMode = AutoCompleteMode.SuggestAppend;
//control.MouseClick += textBox5_MouseClick;
}
control.Name = "Text" + i;
control.Text = "Row" + rowNum + " Text" + i;
}
whitePanel.Controls.Add(control);
controlX += 120 + controlDistance;
}
panel1.Controls.Add(whitePanel);
whitePanel.BringToFront();
rowNum++;
}
private void _button_MouseClick(object sender, EventArgs e) {
//button does its job here
((Button)sender).Parent.Parent.Controls.Remove(((Button)sender).Parent);
}
public SqlConnection Conn { get; }
void save() {
foreach(Panel whitePanel in panel1.Controls) {
var sqlString = "INSERT INTO products(productField, quantityField, unitField, priceField, purchaseField, sellPriceField) VALUES (";
foreach (Control control in whitePanel.Controls) {
if(!(control is Label) && !(control is Button)) { //So, textbox or combobox remained
sqlString += "'"+ control.Text +"', ";
}
}
sqlString = sqlString.Substring(0, sqlString.Length - 2) + ")";
//Assume you have previous construction of SqlConnection as name "Conn"
if (Conn != null) {
if (Conn.State != ConnectionState.Open) Conn.Open();
using (var cmd = new SqlCommand(sqlString, Conn)) {
cmd.ExecuteNonQuery();
}
Conn.Close();
}
Console.WriteLine(sqlString);
}
}
I have tested and works as expected. If it is not suit your needs, make me know.
I have a list view in which each row contains 5 entries. The list box looks like this:
I need to store (display) the name of variable and the value present in "Physical value" column text box when i press OK button. For e.g. if i enter 45 in the physical value text box (only one row at a time) then the name of the variable and value "45" should be stored (displayed). I am able to retrieve the name of the variables but not the value of the text box.
My try:
This code will populate the list view with variables and bind it to the properties.
public void Populatevariables(IList<string> variables)
{
int rowcount = 0;
dataGrid.RowDefinitions.Clear();
dataGrid.ColumnDefinitions.Clear();
RowDefinition rd = new RowDefinition();
rd.Height = new GridLength();
dataGrid.RowDefinitions.Add(rd);
dataGrid.RowDefinitions.Add(new RowDefinition());
dataGrid.ColumnDefinitions.Add(new ColumnDefinition());
Label t1 = new Label();
t1.Content = "Variables";
Grid.SetColumn(t1, 0);
Grid.SetRow(t1, rowcount);
dataGrid.Children.Add(t1);
ListView VrblPopulateList = new ListView();
GridView g1 = new GridView();
g1.AllowsColumnReorder = true;
//l1.View = g1;
GridViewColumn g2 = new GridViewColumn();
g2.Header = "Name";
g2.Width = 200;
g2.DisplayMemberBinding = new Binding("Name");
g1.Columns.Add(g2);
GridViewColumn g5 = new GridViewColumn();
g5.Header = "DataType";
g5.Width = 200;
g5.DisplayMemberBinding = new Binding("DataType");
g1.Columns.Add(g5);
GridViewColumn g3 = new GridViewColumn();
g3.Header = "Current Value";
g3.Width = 200;
DataTemplate dt1 = new DataTemplate();
FrameworkElementFactory FF1 = new FrameworkElementFactory(typeof(TextBox));
FF1.SetBinding(TextBox.BindingGroupProperty, new Binding("Current_Value"));
FF1.SetValue(FrameworkElement.HeightProperty, Height = 30);
FF1.SetValue(FrameworkElement.WidthProperty, Width = 150);
dt1.VisualTree = FF1;
g3.CellTemplate = dt1;
g1.Columns.Add(g3);
GridViewColumn g6 = new GridViewColumn();
g6.Header = "Physical Value";
g6.Width = 200;
DataTemplate dt2 = new DataTemplate();
FrameworkElementFactory FF2 = new FrameworkElementFactory(typeof(TextBox));
FF2.SetBinding(TextBox.BindingGroupProperty, new Binding("Physical_Value"));
//FF2.AddHandler(TextBox.TextChangedEvent, txtchanged, true);
FF2.SetValue(FrameworkElement.HeightProperty, Height = 30);
FF2.SetValue(FrameworkElement.WidthProperty, Width = 150);
dt2.VisualTree = FF2;
g6.CellTemplate = dt2;
g1.Columns.Add(g6);
GridViewColumn g4 = new GridViewColumn();
g4.Header = "Action";
g4.Width = 200;
DataTemplate dt = new DataTemplate();
FrameworkElementFactory FF = new FrameworkElementFactory(typeof(Button));
FF.SetBinding(Button.BindingGroupProperty, new Binding("ToDo"));
FF.SetValue(FrameworkElement.HeightProperty,Height = 30);
FF.SetValue(FrameworkElement.WidthProperty, Width = 150);
FF.SetValue(System.Windows.Controls.Button.ContentProperty,"OK");
FF.AddHandler(Button.ClickEvent, new RoutedEventHandler(b1_click));
dt.VisualTree = FF;
g4.CellTemplate = dt;
g1.Columns.Add(g4);
VrblPopulateList.View = g1;
Grid.SetRow(VrblPopulateList, rowcount + 1);
dataGrid.Children.Add(VrblPopulateList);
for (int i = 0; i < variables.Count; i++)
{
Label lb1 = new Label();
lb1.Content = variables[i].Name;
Label lb2 = new Label();
lb2.Name = variables[i].datatype;
DataTemplate dd = new DataTemplate();
TextBox tb = new TextBox();
tb.Name = "TextBox" + i.ToString();
Button b1 = new Button();
VrblPopulateList.Items.Add(new User() { Name = lb1.Content, DataType = lb2.Name, Current_Value = tb, Physical_Value = tb, ToDo = b1 });
}
}
This code defines the property which is bind while populating:
public class User
{
public object Name { get; set; }
public string DataType { get; set; }
public Control Current_Value
{
get;
set;
}
public Control Physical_Value
{
get;
set;
}
public Control ToDo { get; set; }
}
At last this code will retrieve all the items when button is clicked.
private void b1_click(object sender, RoutedEventArgs e)
{
User item = (User)((Button)sender).DataContext;
TextBox t = (TextBox)item.Physical_Value;
MessageBox.Show(item.Name.ToString() + t.Text);
}
The text box value is always empty. I know it can be solved by adding handler to "text changed" event while populating. But i dont know how to do it. Please help.
As mentioned in the comment by #Ponas Justas i have to do following changes in my code:
Set the UpdateSourceTrigger property of the text box.
Change the user model accordingly.
After doing above changes my code looks like:
FF2.SetBinding(TextBox.BindingGroupProperty, new Binding("Physical_Value"));
FF2.SetBinding(TextBox.TextProperty, new Binding("PhysicalValueTxtChanged") { UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });
User Model
public class User
{
public object Name { get; set; }
public string DataType { get; set; }
public Control Current_Value
{
get;
set;
}
public string _PhysicalValueTxtChanged = null;
public string PhysicalValueTxtChanged
{
get { return _PhysicalValueTxtChanged; }
set
{
_PhysicalValueTxtChanged = value;
}
}
public Control ToDo { get; set; }
}
After doing that the text in the text box can be easily stored by just modifying like this:
private void b1_click(object sender, RoutedEventArgs e)
{
User item = (User)((Button)sender).DataContext;
string txt = item.PhysicalValueTxtChanged;
MessageBox.Show(item.Name.ToString() + txt);
}
Thanks a lot Ponas Justas.
I have in XAML a Window Resource Style targeted at TextBoxes, which style triggers and validations. These work great with my XAML TextBoxes. So far, so good.
What I'd like to do differs from this situation that the TextBoxes are created dynamically, not in XAML.
Please take special attention that there's a parameter to be passed to the ValidationRule, named WhatToCheck.
Here is my code so far:
private StackPanel NumberList(string queryLabel, string businessModelObjectName)
{
TestData currentTestData = dTestDataHolder["CurrentTestData"];
StackPanel spNumberList = new StackPanel();
spNumberList.Orientation = Orientation.Horizontal;
spNumberList.FlowDirection = System.Windows.FlowDirection.RightToLeft;
spNumberList.Margin = new Thickness(0, 0, 0, 10);
Label lNumberList = new Label();
lNumberList.Content = queryLabel;
lNumberList.FontSize = 16;
lNumberList.FontWeight = FontWeights.Bold;
spNumberList.Children.Add(lNumberList);
TextBox tbNumberList = new TextBox();
tbNumberList.Margin = new Thickness(10, 0, 0, 0);
tbNumberList.FontSize = 16;
tbNumberList.VerticalContentAlignment = VerticalAlignment.Center;
tbNumberList.FontFamily = new FontFamily("Courier New");
tbNumberList.Width = 100;
tbNumberList.AcceptsReturn = false;
tbNumberList.FlowDirection = FlowDirection.LeftToRight;
spNumberList.Children.Add(tbNumberList);
Binding bindingNumberList = new Binding(businessModelObjectName);
bindingNumberList.Source = currentTestData;
bindingNumberList.Mode = BindingMode.TwoWay;
tbNumberList.SetBinding(TextBox.TextProperty, bindingNumberList);
return spNumberList;
}
public class GenericValidationRule : ValidationRule
{
public string WhatToCheck{ get; set; }
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
var enteredString = value as string;
switch (WhatToCheck)
{
case "No Extension":
{
if (enteredString.IndexOf(".doc", StringComparison.InvariantCultureIgnoreCase) >= 0)
{
return new ValidationResult(false, String.Format("SOMETHING"));
}
break;
}
case "Only Numbers":
{
double dDummy;
if (!double.TryParse(enteredString, out dDummy))
{
return new ValidationResult(false, String.Format("SOMETHING"));
}
break;
}
default:
break;
}
return new ValidationResult(true, null);
}
}
Using c# and Visual Studio 2013.
No MVVM.
Thanks!
I ended up doing this. Worked great,
Binding bindingNumberList = new Binding(businessModelObjectName);
bindingNumberList.Source = currentTestData;
bindingNumberList.Mode = BindingMode.TwoWay;
bindingNumberList.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
bindingNumberList.ValidatesOnDataErrors = true;
GenericValidationRule gvrCheckValidImageNubers = new GenericValidationRule();
gvrCheckValidImageNubers.ValidationStep = ValidationStep.RawProposedValue;
gvrCheckValidImageNubers.WhatToCheck = "Contains Existing Image Numbers";
bindingNumberList.ValidationRules.Add(gvrCheckValidImageNubers);
tbNumberList.SetBinding(TextBox.TextProperty, bindingNumberList);
I am currently working on a WPF project that uses Caliburn.Micro and have hit a snag I was hoping you could help with. I have a form that allows the user to add new fields to a separate form with the intention that these new fields will persist. I am able to create these controls dynamically with the following code:
Grid tmpOuterGrid = new Grid();
RowDefinition rowDefinition1 = new RowDefinition();
RowDefinition rowDefinition2 = new RowDefinition();
rowDefinition1.Height = new GridLength(45, GridUnitType.Star);
rowDefinition2.Height = new GridLength(55, GridUnitType.Star);
tmpOuterGrid.RowDefinitions.Add(rowDefinition1);
tmpOuterGrid.RowDefinitions.Add(rowDefinition2);
tmpOuterGrid.Margin = new Thickness(0,0,0,10);
Grid tmpInnerGrid = new Grid();
Grid.SetRow(tmpInnerGrid, 0);
tmpInnerGrid.Margin = new Thickness(10,0,0,5);
tmpInnerGrid.Opacity = 0;
DataTrigger d = new DataTrigger();
Binding b = new Binding("DisplayFieldName");
b.Source = _fieldNames[primaryNameBase + "FieldTextBox"];
d.Binding = b;
d.Value = true;
Storyboard sbEnter = new Storyboard();
DoubleAnimation opAnimShow = new DoubleAnimation(1,new Duration(new TimeSpan(0,0,0,1)));
Storyboard.SetTargetProperty(sbEnter, new PropertyPath(UIElement.OpacityProperty));
sbEnter.Children.Add(opAnimShow);
Storyboard sbExit = new Storyboard();
DoubleAnimation opAnimHide = new DoubleAnimation(0, new Duration(new TimeSpan(0, 0, 0, 1)));
Storyboard.SetTargetProperty(sbExit, new PropertyPath(UIElement.OpacityProperty));
sbExit.Children.Add(opAnimHide);
BeginStoryboard bsEnter = new BeginStoryboard { Storyboard = sbEnter, Name = "beginStoryboardEnter" };
BeginStoryboard bsExit = new BeginStoryboard { Storyboard = sbExit, Name = "beginStoryboardExit" };
d.EnterActions.Add(bsEnter);
d.ExitActions.Add(bsExit);
Style st = new Style(typeof(Grid));
st.Triggers.Add(d);
tmpInnerGrid.Style = st;
TextBlock tb = new TextBlock();
tb.Name = primaryNameBase + "FieldHeaderText";
tb.Foreground = new SolidColorBrush(Color.FromArgb(136,255,255,255));
tb.FontSize = 14;
tb.Style = (Style) App.Current.Resources["NexaLightTextBlock"];
tb.HorizontalAlignment = HorizontalAlignment.Center;
tb.Text = fieldTextBox.DisplayText;
Border underline = new Border();
underline.BorderThickness = new Thickness(0, 0, 0, 1);
underline.BorderBrush = new SolidColorBrush(Color.FromArgb(136,49,250,250));
underline.VerticalAlignment = VerticalAlignment.Bottom;
underline.HorizontalAlignment = HorizontalAlignment.Center;
Binding binding = new Binding
{
Source = tb,
Path = new PropertyPath("ActualWidth"),
};
underline.SetBinding(FrameworkElement.WidthProperty, binding);
tmpInnerGrid.Children.Add(tb);
tmpInnerGrid.Children.Add(underline);
LowBorderTextBox lbtb = new LowBorderTextBox();
lbtb.Name = primaryNameBase + "FieldTextBox";
Grid.SetRow(lbtb, 1);
lbtb.Width = 140;
lbtb.Margin = new Thickness(10,0,0,0);
lbtb.FontColor = new SolidColorBrush(Colors.White);
lbtb.DisplayFontSize = 22;
lbtb.Style = (Style) App.Current.Resources["NexaLightCustomTextBox"];
lbtb.DisplayText = fieldTextBox.DisplayText;
lbtb.LostFocus += FieldLostFocus;
tmpOuterGrid.Children.Add(tmpInnerGrid);
tmpOuterGrid.Children.Add(lbtb);
wrapPanel.Children.Add(tmpOuterGrid);
I would then like these new controls to be persisted through application shutdowns. The approach I was thinking of taking was serializing the object into xaml and storing that in a file, and then reading this file and deserializing it to obtain the control object again, which would be added to my surrounding WrapPanel. This is all fine and dandy except for one detail. The controls that are created have a style with a datatrigger that is bound to a property of a NoteField object, there being one NoteField object for each of these types of control. I was planning on serializing the NoteField objects as well, so that I could just pull them back and hope that the binding would still be intact, but they implement the PropertyChangedBase interface of the Caliburn.Micro framework, and the NotifyOfPropertyChange() method is not marked as serializable. Here is the NoteField class:
[Serializable]
class NoteField : PropertyChangedBase
{
private string _controlName;
private bool _displayFieldName;
public bool DisplayFieldName
{
get { return _displayFieldName; }
set
{
_displayFieldName = value;
NotifyOfPropertyChange(() => DisplayFieldName);
}
}
private string _fieldName;
public string FieldName
{
get { return _fieldName; }
set
{
_fieldName = value;
NotifyOfPropertyChange(() => FieldName);
}
}
public NoteField(string controlName, string displayText)
{
DisplayFieldName = false;
_controlName = controlName;
FieldName = displayText;
}
public string GetControlName()
{
return _controlName;
}
public void SetControlName(string name)
{
_controlName = name;
}
}
I am not attached to using this class, but it was the only way I could think of having dynamically generated properties to bind to from the xaml. So, I guess my question is: is there a way that I can dynamically create controls that have bindings in them that can persist through application shutdowns? Am I on the right track, or should I do something else all together? Any help would be greatly appreciated. Thank you so much for your time.