Set properties on dynamically added UserControl - c#

I'm dynamically adding a custom user control to the page as per this post.
However, i need to set a property on the user control as i add it to the page. How do I do that?
Code snippet would be nice :)
Details:
I have a custom user control with a public field (property ... e.g. public int someId;)
As I add a UserControl to a page, its type is UserControl. Do i just cast it into MyCustomUCType and set a property on a cast control?
p.s. looks like I've answered my own question after all.

Ah, I answered before you added the additional clarification. The short answer is, yes, just cast it as your custom type.
I'll leave the rest of my answer here for reference, though it doesn't appear you'll need it.
Borrowing from the code in the other question, and assuming that all your User Controls can be made to inherit from the same base class, you could do this.
Create a new class to act as the base control:
public class MyBaseControl : System.Web.UI.UserControl
{
public string MyProperty
{
get { return ViewState["MyProp"] as string; }
set { ViewState["MyProp"] = value; }
}
}
Then update your user controls to inherit from your base class instead of UserControl:
public partial class SampleControl2 : MyBaseControl
{
....
Then, in the place where you load the controls, change this:
UserControl uc = (UserControl)LoadControl(controlPath);
PlaceHolder1.Controls.Add(uc);
to:
MyBaseControl uc = (MyBaseControl)LoadControl(controlPath);
uc.MyProperty = "foo";
PlaceHolder1.Controls.Add(uc);

"As I add a UserControl to a page, its
type is UserControl. Do i just cast it
into MyCustomUCType and set a property
on a cast control?"
That's what I'd do. If you're actually using the example code where it loads different controls, I'd use an if(x is ControlType) as well.
if(x is Label)
{
Label l = x as Label;
l.Text = "Batman!";
}
else
//...
Edit: Now it's 2.0 compatible

Yes, you just cast the control to the proper type. EX:
((MyControl)control).MyProperty = "blah";

Related

Hiding base class dependency property in derived control

I am writing a set of custom TextBox controls for different data types. I do not only want the text to be validated (which I do) but also store the input in a property of adequate type.
So for example I have an UnsignedIntegerBox which inherits from TextBox, should store the input in an "uint UnsignedInteger" property, whith default set in xaml. It validates the input in the OnPreviewTextInput event. The OnTextChanged is used to update the UnsignedInteger from Text.
Question: Is there any way to hide the TextBox.Text property so that it is not exposed (and cannot be used) in XAML ?
I would suggest to create new CustomTextbox class that could inherit from UserControl / Control class, create a DP property on it as you want and bind it to a TextBox in Control template / Content of your new control. So that you still use TextBox for input/visuals but from code point it is hidden behind your new CustomTextBox class
When you extend a superclass, then the subclass is the superclass. You can never remove any members of the superclass. You can change the behavior by overriding virtual members or hiding accessible members. Maybe you should revisit the inheritance rules of OO languages like C# to understand the concept.
This is what you can do, where 3, 4, 5 are the only clean and useful solutions:
When you hide the Text property to declare it private, then you would get a XAML error, due to the type inference of the XAML engine. This way the Text property is available via Intellisense, but you can't set it. But in C# the next accessible member is chosen. The member lookup behavior will automatically exclude the new hiding private Text property and will then find the public superclass member.
class MyTextBox : TextBox
{
// Only has an effect in XAML
new private string Text { get; set; }
}
Even if this would work, you could always set the static DependencyProperty using the DependencyObject.SetValue method. Hiding is also only hiding and not removing. You can always cast to the superclass to get access to the original Text property.
You can override the DependencyProperty meta data to disallow data binding
public class MyTextBox : TextBox
{
static MyTextBox()
{
TextBox.TextProperty.OverrideMetadata(
typeof(MyTextBox),
new FrameworkPropertyMetadata(default, FrameworkPropertyMetadataOptions.NotDataBindable));
}
}
This will throw an exception if you try to bind to the Text property.
But you can still set the value via assignment.
Use composition over inheritance. You can the design the class API to your requirements and delegate the functionality to the inaccessible composition type.
// Alternatively extend Control
class MyTextBox : TextBoxBase
{
private TextBox TextBox { get; }
public int Number
{
get => return this.TextBox.Text;
set
{
if ( IsValid(value))
{
this.TextBox.Text = value;
}
}
}
Extend the class in the type hierarchy that does not declare the unwanted members. In your case this would be TextBoxBase.
// Will not have a Text property
class MyTextBox : TextBoxBase
{
}
Throw a NotSupportedException exception to make using the inherited members impossible. The developer is immediately notified that e.g., the Text property is not availble. May not be the best solution for public libraries.
public class MyTextBox : TextBox
{
static MyTextBox()
{
TextBox.TextProperty.OverrideMetadata(
typeof(MyTextBoxl),
new FrameworkPropertyMetadata(null, OnCoerceText));
}
private static object OnCoerceText(DependencyObject d, object baseValue)
=> throw new NotSupportedException();
}

How to Typecaste a control and access its properties?

IDE: Visual Studio, C# .net 4.0
I have two identical user control uc1 and uc2 and both are having a textbox called txtbox1
now see this code and textbox1 is public in designer so it is assessable in form1.cs, Form 1 is simple windows form which is having uc1 and uc2.
In form1 see this function which i am calling in onLoad_form1 method.
UserControl currentUC; //Global variable;
public void loadUC(string p1)
{
//Here I want:
if(p1 == "UC1)
{
currentUC = uc1;
}
if(p1 == "UC2)
{
currentUC = uc2;
}
}
Than another function which calls update the textbox1 based on currentUC value
//on load
currentUC.textbox1.text = "UC1 called";
//Here I am getting error "currentUc does not contains definition for textbox1"
If i do:
uc1.textbox1.text = "UC1 text";
uc2.textbox1.text = "UC1 text"; //it works, But based on p1 string variable I want to make control as uc1 or uc2 than I want to access its child control. please suggest how to perform this.
please don't tell if else blocks, because This functionality I have to use in various places.
Thanks.
#Lee Answer: - works just for textbox, but I am having two usercontrols i.e. two different usercontrols not instance of it. UserControlLeft and UserControlRight and both are having same textboxes, listboxes etc (with minor design changes), and I want to access/load this based on some string "left" and "right".
Since the textboxes have the same name you can look them up in the Controls collection:
TextBox tb = (TextBox)currentUC.Controls["textbox1"];
tb.Text = "UC1 called";
a better solution would be to add a property to your user control class which sets the internal text property e.g.
public class MyUserControl : UserControl
{
public string Caption
{
get { return this.textbox1.Text; }
set { this.textbox1.Text = value; }
}
}
I think you're mixing a couple of things here.
First of all, you say that you have 2 exactly the same usercontrols, do you mean the ascx files are the same, or that you have 2 instances of the same usercontrol on the page?
Let's go with all the valid options:
1. To find a control and cast it:
Assume you have the following aspx snippet:
<div>
<uc1:MyCustomUserControl id="myControl" runat="server" />
<uc1:MyCustomUserControl id="myControl2" runat="server" />
</div>
If you now want to access the control, you should do the following:
public void Page_Load()
{
var myControl ((MyCustomUserControl)FindControl("MyControlName"));
// On 'myControl' you can now access all the public properties like your textbox.
}
In WPF you can do it like this:
//on load MAINFORM
public void SetText(string text)
{
CLASSOFYOURCONTROL ctrl = currentUC as CLASSOFYOURCONTROL ;
ctrl.SetText(text);
}
// in your control SUB
public void SetText(string text)
{
textbox1.text = "UC1 called"
}
i think this should work in winforms also. And is more clean than accessing the controls from your sub-control directly
#Lee's method is good. Another method will be to use a public property with a public setter (and textbox doesn't need to be public this way).
or an interface (this way you don't care what class you have at the given moment - and no ifs):
public interface IMyInterface
{
void SetTextBoxText(string text);
}
public partial class UC1: UserControl, IMyInterface
{
public void SetTextBoxText((string text)
{
textBox1.Text=text;
}
//...
}
public partial class UC2: UserControl, IMyInterface
{
public void SetTextBoxText((string text)
{
textBox1.Text=text;
}
//...
}
using the code:
((IMyInterface)instanceOfUC1).SetTextBoxText("My text to set");
((IMyInterface)instanceOfUC2).SetTextBoxText("My text to set");

How to pass value to constructor from xaml?

I want to assign a value right when initializing a new UserControl:
public partial class MyUserControl : UserControl
{
public MyUserControl(int id)
{
InitializeComponent();
//.. do something with id
}
// ...
}
Is it possible to pass a value to constructor (id in my case) from xaml?
<CustomControls:MyUserControl />
(Yes I can define a dependency property or make the control in code behind, but that doesn't help)
Yeah, that's possible. You can create a user control programmatically. Then, you can use any constructor you want. Here's a sample:
Supposing, that we have a usercontrol, that assigns a value to textbox on initialization:
public ControlWithP(int i)
{
InitializeComponent();
tb.Text = i.ToString();
}
Add this control to page:
public SamplePage()
{
InitializeComponent();
ControlWithP cwp = new ControlWithP(1);
this.sp.Children.Add(cwp);
}
where sp is StackPanel control. Same thing with adding user control to Grid.
see the result.
Is this, what you wanted?
From XAML-2009 you could do this with x:Arguments Directive but Windows Phone is using 2006 (for now) so it is not possible.
So to use your control from XAML you need a default contructor (parameterless).
I think you could use a little workaround, by using specially designed property for this:
public partial class MyControl : UserControl
{
private string myValue = "Default";
public string MyValue
{
get { return myValue; }
set
{
myValue = value;
// alternatively you can add some code here which
// will be invoked after control is created
}
}
public MyControl()
{
InitializeComponent();
}
}
then in XAML:
<local:MyControl MyValue="From xaml"/>
Just after the control is created, the property is set and its code invoked - so it can alternatively be used as additional part of code run during creation.
If you want to pass data to your control, better choice would be DependencyProperty - example here.

Finding controls in WPF ControlTemplate

I have created class that inherits from Window and I am applying control template to it:
public class BaseSearchWindow : Window {
static BaseSearchWindow() {
DefaultStyleKeyProperty.OverrideMetadata(typeof(BaseSearchWindow), new FrameworkPropertyMetadata(typeof(BaseSearchWindow)));
}
public BaseSearchWindow() {
Uri uri = new Uri("/WPFLibs;component/Resources/StyleResources.xaml", UriKind.Relative);
ResourceDictionary Dict = Application.LoadComponent(uri) as ResourceDictionary;
this.Style = Dict["WindowTemplate"] as Style;
}
Than I want to find some control in control template:
public override void OnApplyTemplate() {
RibbonCommand searchCommand = this.Template.FindName("searchCommand", this) as RibbonCommand;
//doesn't work, searchCommand is null
searchCommand.CanExecute += CanExecuteRibbonCommand;
}
But it is allways null.
I tried it in inherited class and it works, but I want it in my base class, so I don't have to search for it every time I use that class.
This works:
public partial class MainWindow : BaseSearchWindow {
public MainWindow() {
InitializeComponent();
RibbonCommand searchCommand = this.Template.FindName("searchCommand", this) as RibbonCommand;
searchCommand.CanExecute += CanExecuteRibbonCommand;
}
Using FindName in OnApplyTemplate is the correct way of doing it; I think it doesn't work because you forgot to call base.OnApplyTemplate().
My bet is that you are looking for a command that doesn't exist (or has a different name) or isn't a RibbonCommand.
That or you didn't specify x:FieldModifier="protected" for the command in xaml.
Actually, I made a mistake. When I try to find controls that are not RibbonCommands it worked, so now I find parent control first and than use VisualTreeHelper to find the RibbonCommand. Sorry about that, I was convinced that it worked only in extended class, but I guess I was too tired when I posted the question. Thank you for your help anyway.

accessing controls on parentform from childform

I want to change text in textbox on parentform from childform.
I set textbox
modifiers= public
i have extra written a function in parentform
public TextBox txtbox
{
get
{
return mybox;
}
set
{
mybox= value;
}
}
in child form on writing
this.ParentForm. ( can't see mybox).
what i am missing.
regards,
Since ParentForm will return a Form and not your form, you need to cast it before you can access any of your custom properties:
((MyForm)this.ParentForm).textbox = "new text!";
Additionally, you are setting the whole control, not just the text.
Try this, to expose the text property only:
public string txtbox
{
get
{
return mybox.Text;
}
set
{
mybox.Text = value;
}
}
I think the problem is that ParentForm is of type Form which does not have a member txtbox. You need to cast ParentForm to your form (suppose it is Form1), like:
((Form1)this.ParentForm).txtbox
Random guess without seeing any actual code: mybox is likely not declared public.
Edit: Or, ah, yes, as Andrei says - you havn't cast the ParentForm to your parent form's type.

Categories

Resources