I would like an additional WPF control that would add an int property to the TextBox class. I have tried Project > Add New Item > Custom Control (WPF). That gave me a new cs file for the new Control. I tried just having this new class inherit TextBox class and then adding public int number { get; set; } inside static CustomTextBox() but apparently that is not the correct syntax.
The TextBoxs I need this for are to be created dynamically in code, not in XAML.
Here is my attempt at implementing John Gardner's answer:
public static readonly DependencyProperty Number = DependencyProperty.RegisterAttached(
"number",
typeof(TextBox),
typeof(int),
new PropertyMetadata(false)
);
public static void SetNumber(UIElement element, TextBox value)
{
element.SetValue(Number, value);
}
public static TextBox GetNumber(UIElement element)
{
return (TextBox)element.GetValue(Number);
}
I added this in the MainWindow Class. It does not appear to give my TextBoxs the additional Number property.
You could just create a subclass of TextBox and add a single int property to it. That should do it I guess.
Take a look at this code to see an example of how to do it:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
panel.Children.Add(new MyTextBox { Number = 123 });
panel.Children.Add(new MyTextBox { Number = 321 });
panel.Children.Add(new MyTextBox { Number = 456 });
panel.Children.Add(new MyTextBox { Number = 654 });
}
private void click(object sender, RoutedEventArgs e)
{
var myTextBoxes = panel.Children.OfType<MyTextBox>();
var numbers = string.Empty;
myTextBoxes.ToList().ForEach(p => numbers += p.Number + Environment.NewLine);
MessageBox.Show(numbers);
}
}
//Subclass of TextBox that just adds one property
public class MyTextBox : TextBox
{
public int Number { get; set; }
}
..and the XAML just has the panel and a button:
<StackPanel Name="panel">
<Button Content="Show numbers" Click="click" />
</StackPanel>
Do you need a new control? You might be better off using an attached property instead. then no new control at all.
http://msdn.microsoft.com/en-us/library/cc265152(v=VS.95).aspx
Update:
an attached property doesn't add a property to the textbox directly, you'd access it like
YourClass.SetNumber( textbox, value );
int value = YourClass.GetNumber( textbox );
or in xaml,
<TextBox YourClass.Number="1"/>
your property should be "Number" in its string definition as well, you have "number". And your Get/Set calls should have an int value, not a textbox.
Related
Beginner here.
I have a list on my MainPage that I am adding items to by typing stuff into a textbox submitting it. After creating a listview item, I would like to be able to click on an item and see its value in another page.
I created a DetailsPage for this, but I don't know what the best way is to share that data across these pages.
This is what I have in my MainPage so far:
public sealed partial class MainPage : Page
{
public int itemCounter;
public MainPage()
{
this.InitializeComponent();
//This is the button that submits the entered text
public void btnSubmitInPopup_Click_1(object sender, RoutedEventArgs e)
{
//Create new listview item and textblock
ListViewItem item = new ListViewItem();
TextBlock txtBloodSugarValue = new TextBlock();
//Save text input value to label and add item to list
txtBloodSugarValue.Text = txtInput.Text;
item.Content = txtBloodSugarValue;
mainListView.Items.Add(item);
//Reset text input field
txtInput.Text = "";
//Update counter of items in list
itemCounter = mainListView.Items.Count();
lblItemCounter.Text = itemCounter.ToString();
}
}
My DetailPage literally has just one label that I am trying to populate with whatever value is in the listview item that I clicked on in my MainPage.
What's the best way to do this?
Hope this makes sense.
Thanks so much.
You have 3 way to do that:
declaring static variable and set that in first form and use in second form(or anywhere!)
Create public field/propeey inside second form class and set it from first form
Pass value as parameter to constructor/function of second class
I add second form class here:
public static int StaticVariable { get; set; }//First Method
public int PublicProperty { get; set; }
public Form2(int Value)
{
InitializeComponent();
//Do your code here with constructor way here
}
public Form2()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
//Do your code for 1,2 here
}
public void SetValueWithFunction(int value)
{
//Do your code for setting value with second type in Number 3
}
I hope this helps :)
I need to create custom comboboxitem wich i can process among other controls that inherit System.Windows.Forms.Control class. So my comboboxitem must inherit System.Windows.Forms.Control because i use cast to that type and refer to Text property withn a loop.
There is some posts on how to create custom item but that one inherits Object class which is not working for me? I tried but it didnt work?Here is my try:
public class ComboItem : System.Windows.Forms.Control
{
public object Value { get; set; }
public override string Text { get; set; }
// public object Value { get; set; }
public ComboItem(string text) { this.Text = text; }
public ComboItem(string text, string value) { this.Text = text; this.Value = value; }
public override string ToString()
{
return Text;
}
}
nothing is displayed in combo box after following code
private void Form1_Load(object sender, EventArgs e)
{
ComboItem asd = new ComboItem("qweqwwqeq");
ComboItem asd2 = new ComboItem("2222222");
comboBox1.Items.Add(asd);
comboBox1.Items.Add(asd2);
comboBox1.SelectedIndex = 1;
}
this is context in which i need to use it:
System.Windows.Forms.Control ctrl = (System.Windows.Forms.Control)asd["Kontrola"];
ctrl.Text = (String)asd["Engleski"];
I assume you are not really talking about the ComboBoxItem Class, which is from WPF but simply of the Winforms Combobox which contains objects.
For some reason Controls don't get displayed in Collections unless they are actually placed in a Container Control.
So you probably have to wrap your Control in a minimal wrapper class like this:
class CtlWrapper
{
public Control theControl { get; private set; }
public CtlWrapper(string text)
{
theControl = new Control();
theControl.Text = text;
}
public CtlWrapper(Control control) { theControl = control; } // for fun
public override string ToString() { return theControl.Text; }
}
Not sure what you'll do with such a generic thing as Control in the ComboBox's Items list, but maybe you'll add some code to create different Control types..? With the wrapper the ToString text gets displayed as expected..
Of course you an add a Value string or whatever you need to the class as needed or you could use your own class as the type of 'theControl'..
Edit: For fun I have added a 2nd constructor to allow for adding existing Controls (of any type ;-)
In a nutshell, I want to use DataContext binding to assign a label the value of a public automatic property in another class.
So I have a class containing a public automatic property like so:
public class MyData
{
public string DogName { get; set; }
}
My WPF form looks like this:
The CodeBehind for my WPF form is as so:
public partial class MainWindow : Window
{
private MyData myData;
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
myData = new MyData();
myData.DogName = "Lulu";
label1.DataContext = myData.DogName;
}
}
This isn't, however, changing the value of label1 to "Lulu", it just stays at "Label". What have I missed out?
Thanks
That is not exactly the common way to work with DataContexts (as you show it, MyData as a class serves no purpose at all).
Try this instead:
//C#
label1.DataContext = new MyData{ DogName = "Lulu" };
//xaml
<Label Content="{Binding Path=DogName}"/>
now, you could for instance also use MyData to contain the label's Width or so.
Another (probably most used) way is to set the parent's DataContext, and make the individual elements use it's properties:
//C#
class MyData
{
public strig DogName{ get; set; }
public strig CatName{ get; set; }
}
this.DataContext = new MyData{ DogName = "Lulu", CatName = "Fifi" };
//xaml
<Label Content="{Binding Path=DogName}"/>
<Label Content="{Binding Path=CatName}"/>
I am trying to move the following function listView_SelectionChanged away from code-behind and handle it directly inside my ViewModel (or directly as XAML). And I was hoping that someone might have a better idea on how to implement this.
The TextBox contains Sections e.g. [Secion1] and to help navigate I have a ListBox on the side of the TextBox that contains a list of all Sections. If you click on one of the Sections it will automatically jump to that part of the Text.
The code currently looks something like this:
XAML
ListBox ItemsSource="{Binding Path=Sections}" Name="listBox"
SelectionMode="Single" Width="170"
DisplayMemberPath="Section"
SelectionChanged="listView_SelectionChanged"/>
<TextBox Name="TextBox1" Text="{Binding Path=Source}"/>
Model
public class SourceData
{
public SourceData()
{
Sections = new List<SectionData>();
}
public String Source { get; set; }
public List<SectionData> Sections { get; set; }
}
public class SectionData
{
public int Line { get; set; } // Line of the Section
public String Section { get; set; } // Section name (e.g. [Section1]
}
Code-behind
private void listView_SelectionChanged(object sender,
System.Windows.Controls.SelectionChangedEventArgs e)
{
var test = (SectionData)listBox.SelectedItem; // Get Information on the Section
if (test.Line > 0 && test.Line <= TextBox1.LineCount) // Validate
{
TextBox1.ScrollToLine(test.Line - 1); // Scroll to Line
}
}
In such situations I usually create an attached behavior (in your case it will be a behavior which will allow synchronizing textbox scrolled line), add property in ViewModel (SourceData) which will rule that attached behavior and bind behavior to this property.
Steps you should do in your case (I assume you know how to create an attached properties):
1) Create attached behavior ScrolledLine for textbox. It should support at least one-way binding. In attached property callback you will scroll textBox (to which behavior is attached) to the line. Below you will find a quick sample how to implement such a behavior.
2) Your SourceData should be extended with at least two properties: SelectedSection and ScrolledLine. ScrolledLine should be raising PropertyChanged. SelectedSection setter should change ScrolledLine:
private SectionData _selectedSection;
public SectionData SelectedSection
{
get { return _selectedSection; }
set
{
_selectedSection = value;
if (_selectedSection != null) SelectedLine = _selectedSection.Line;
}
}
3) Bind your view to these two new properties:
b below is xml-namespace for your attached behavior from #1
<ListBox ItemsSource="{Binding Path=Sections}" SelectionMode="Single" Width="170" DisplayMemberPath="Section" SelectedItem="{Binding SelectedSection, Mode=TwoWay}" />
<TextBox Text="{Binding Path=Source}" b:Behaviors.ScrolledLine="{Binding ScrolledLine}" />
4) Remove your listView_SelectionChanged event handler from view. Your view should not have any code except InitializeComponent from now on.
P.S.: Here is a sample how your attached behavior should look like:
public class b:Behaviors
{
#region Attached DP registration
public static int GetScrolledLine(TextBox obj)
{
return (int)obj.GetValue(ScrolledLineProperty);
}
public static void SetScrolledLine(TextBox obj, int value)
{
obj.SetValue(ScrolledLineProperty, value);
}
#endregion
public static readonly DependencyProperty ScrolledLineProperty=
DependencyProperty.RegisterAttached("ScrolledLine", typeof(int), typeof(Behaviors), new PropertyMetadata(ScrolledLine_Callback));
// This callback will be invoked when 'ScrolledLine' property will be changed. Here you should scroll a textbox
private static void ScrolledLine_Callback(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
var textbox = (TextBox) source;
int newLineValue = (int)e.NewValue;
if (newLineValue > 0 && newLineValue <= textBox.LineCount) // Validate
textbox.ScrollToLine(newLineValue - 1); // Scroll to Line
}
}
I am writing an application which is going to allows users to change the properties of a text box or label and these controls are user controls. Would it be easiest to create a separate class for each user control which implements the properties I want them to be able to change and then bind those back to the user control? Or is there another method I am overlooking?
Create a custom Attribute, and tag the properties you want the user to edit with this attribute. Then set the BrowsableAttribute property on the property grid to a collection containing only your custom attribute:
public class MyForm : Form
{
private PropertyGrid _grid = new PropertyGrid();
public MyForm()
{
this._grid.BrowsableAttributes = new AttributeCollection(new UserEditableAttribute());
this._grid.SelectedObject = new MyControl();
}
}
public class UserEditableAttribute : Attribute
{
}
public class MyControl : UserControl
{
private Label _label = new Label();
private TextBox _textBox = new TextBox();
[UserEditable]
public string Label
{
get
{
return this._label.Text;
}
set
{
this._label.Text = value;
}
}
[UserEditable]
public string Value
{
get
{
return this._textBox.Text;
}
set
{
this._textBox.Text = value;
}
}
}