Adding properties to be used in XAML dynamically - c#

is it possible to add dynamic properties to be used in a different class? I mean for example I created a "Leave feedback" button, and when I click it, I want it to send the name of that person to the server. And I want to put the name of those persons when I define those buttons, like:
private void LeaveFeedback(object sender, EventArgs e) {
Button btn = sender as Button;
// I actually do not know how to access that property as well.
// Maybe something like a dictionary to specify the dynamic properties as `PropertyName: PropertyValue` pair would be efficient.
}
<Button Click="LeaveFeedback" FeedbackPerson="some_person" UserID="some_person_id" .../>
<Button Click="LeaveFeedback" FeedbackPerson="some_person_2" UserID="some_person_2_id" .../>
and so on.
How can I do that? Should I declare a specific control?

You could set the Tag property to an instance of a custom or anonymous type:
Button btn = sender as Button;
btn.Tag = new { FeedbackPerson = "some_person", UserID = "some_person_id" };
Retrieval is flexible but untyped and fragile:
dynamic tag = btn.Tag;
string feedbackPerson = tag.FeedbackPerson.ToString();
string iserID = tag.UserID.ToString();
A more elegant solution would be create two attached properties that you can set and get like this:
Behavior.SetFeedbackPerson(btn, "some_person");
string feedbackPerson = Behavior.GetFeedbackPerson(btn);

Related

howto pass dictionary key in a form event C#?

Here is the code that I am running:
private Dictionary<string, List<GuiEvent>> m_events = new Dictionary<string, List<GuiEvent>>();
private void OnRadioBtnCheckedChange(object sender, EventArgs e, string formhandle)
{
RadioButton control = (RadioButton)sender;
GuiEvent evnt = new GuiEvent
{
id = GuiEventType.RadioButtonChange,
ElementName = control.Name,
sparam = control.Text,
lparam = control.Checked ? 1 : 0
};
m_events[formhandle].Add(evnt);
}
Getting the error:
Severity Code Description Project File Line Suppression State
Error CS0123 No overload for 'OnRadioBtnCheckedChange' matches delegate 'EventHandler' MtGuiController C:\Users\AIMS-RESEARCH\Desktop\MtGuiController\MtGuiController\Controller.cs 258 Active
Previously when the m_event was declared like this:
private List<GuiEvent> m_events = null;
And the function:
private void OnRadioBtnCheckedChange(object sender, EventArgs e)
{
RadioButton control = (RadioButton)sender;
GuiEvent evnt = new GuiEvent
{
id = GuiEventType.RadioButtonChange,
ElementName = control.Name,
sparam = control.Text,
lparam = control.Checked ? 1 : 0
};
m_events.Add(evnt);
}
Everything was working fine.
I am not able to understand what I can do in this situation. I cannot declare string formhandle as global as it is changing every time. So please take a note of it. It is C# DLL function.
Can anybody tell me solution that will help?
If you want to use some additional information in your event handler, you cannot pass it as an additional parameter to event handling function. You cannot also change type of event handler parameters - it should just accept two arguments - sender and EventArgs.
You have three options here. First - store data in sender and then access that data in event handler. Simplest way is using radio button's tag. Control.Tag is inherited from base Control class and you can use it to store some data when you create control. I.e. assign appropriate formhandle to every radio button Tag (you can even do that manually via designer)
radioButton1.Tag = "foo";
radioButton2.Tag = "bar";
and then retrieve it in event handler:
private void OnRadioBtnCheckedChange(object sender, EventArgs e)
{
RadioButton control = (RadioButton)sender;
GuiEvent evnt = new GuiEvent
{
id = GuiEventType.RadioButtonChange,
ElementName = control.Name,
sparam = control.Text,
lparam = control.Checked ? 1 : 0
};
var formhandle = (string)control.Tag; // here you get "foo" or "bar"
m_events[formhandle].Add(evnt);
}
Second option - create your custom radio button control. But that's overkill here. Usually, you do that when you need a custom look & feel, not just to pass data.
Third option - lookup data you want using the data you have (e.g. control name). This option makes sense when data you need is not available at the time of control creation or if it changes over time.

Having a reference to a property, Is there a way to grab a reference to the encompassing object?

I have extended the Label class as follows:
public class MyLabel: Label {
public Button btn;
public string mydata;
}
In my main program, I instantiated a new instance:
MyLabel lbl = new MyLabel();
lbl.mydata = "some data here";
lbl.btn = new Button();
lbl.btn.Click += new EventHandler(button_pressed);
this.Controls.Add(lbl); // Adds the label to the form
this.Controls.Add(lbl.btn); // Adds the button to the form
And I created a method to handle the button click event:
void button_pressed(Object sender, EventArgs e) {
Button btn = (Button)sender;
//Now I have an access to the property within MyLabel instance.
// but how can I access the parent object?
// I need to access the sibling property [mydata] string from here
btn.Siblings["mydata"] = "some other thing" ; //Something like this
MyLabel lbl = btn.ParentObject(); //Or something like this
lbl.mydata = "Some other thing";
}
This looks like WinForms, in which case either a UserControl or extending Button class might be a good way to go - just maintain a reference to the parent (a bit more complicated with UserControl, you'd need to define the click event on that control, otherwise you're back to "square 1") I like the Tag property solution as well, although there is an additional cast, and no guarantee of type safety (since Tag is an object, it can be anything by the time you try to access it).
However, let's say you're looking for a more general solution; let's also say that the class in question is sealed, has no Tag or similar purpose property, and a Controls collection is not available (or looping through it is not desirable for performance reasons). To my best knowledge, you can't determine parent object; but you can easily provide your own "Controls" style dictionary, mapping the Button to the parent:
public class MyLabel: Label {
public static Dictionary<Button, MyLabel> ParentMap = new Dictionary<Button, MyLabel>();
public Button btn;
public string mydata;
public void AddToParentMap() => ParentMap[btn] = this;
}
When you're creating an instance of MyLabel, just call the AddToParentMap() function (can't be done in constructor, because this pointer is not available until the object is created):
MyLabel lbl = new MyLabel();
lbl.AddToParentMap();
You can then just look it up, fast and easy, in your click event:
void button_pressed(Object sender, EventArgs e) {
Button btn = (Button)sender;
var label = MyLabel.ParentMap[btn];
//...
//Your code...
}
Unlike the Tag solution, type safety is guaranteed - you always know you're accessing a MyLabel object.
You can't access it through button instance but what you can do is to get MyLabel from Controls collection:
var lbl = this.Controls.OfType<MyLabel>().FirstOrDefault(c => c.btn == btn);
You can use the Tag property.
lbl.btn = new Button();
lbl.btn.Tag = lbl;
And then when you need it:
Button btn = (Button)sender;
Label lbl = (MyLabel)btn.Tag;

Create WPF Function to Hidden Images Controls

I'm currently developing a WPF C# Application that contains some textbox validations. If field is valid it must show a ok validation image if not valid it must show a wrong validation image, like an image below.
My Problem is how to set visibility = visibility.Hidden for all images if I click on cancelar button or another button. I know set img1.visibility = visibility.Hidden;, img2.visibility = visibility.Hidden;, img3.visibility = visibility.Hidden;... Works but i need to create a function to do it. I believe that I create a List of Images and pass this List of parameter to a function works fine and I can use this function for other validations. So how can I do it?
Please check this article : Data Binding
If you implement data binding then you have just to bind properties:
<Image Source="..." Visibility="{Binding Img1Visibility}"/>
Implement ViewModel class via INotifyPropertyChanged
And then simply work with your Properties in code.
UPD
If you want to simply create function to work with your images then move your img1.visibility = visibility.Hidden;, img2.visibility = visibility.Hidden;, img3.visibility = visibility.Hidden; in separate function inside your MainWindow.xaml.cs file, you don't have to pass it as arguments as you work in one MainWindow class.
So simply:
private void Fun()
{
img1.visibility = visibility.Hidden;
img2.visibility = visibility.Hidden;
img3.visibility = visibility.Hidden;
}
And request your Fun() method from ClickButton handler.
Create an array of the image controls and iterate over it.
List<Image> _images = new List<Image>
{
img1,
img2,
...
};
void Cancelar()
{
foreach (var image in _images)
{
image.Visibility = Visibility.Hidden;
}
}
But still, the code is awful. Witness me SO.

Use controls that are created at runtime

I am creating a textbox and a checkbox at runtime:
TextBox tb = new TextBox();
tb.Name = "txtPassword";
tb.PasswordChar = '*';
CheckBox cb = new CheckBox();
cb.Text = "Show Password";
cb.Name = "cbShowPassword";
cb.CheckedChanged += new EventHandler(cbShowPassword_CheckedChanged);
And I want to mask or unmask the password according to the checkbox:
private void cbShowPassword_CheckedChanged(object sender, EventArgs e)
{
txtPassword.PasswordChar = cbShowPassword.Checked ? '\0' : '*';
}
The problem is, it doesn't recognize txtPassword and cbShowPassword under cbShowPassword_CheckedChanged, since it is created in the code.
How can I make it work?
As it stands, you use a local variable tb in the method in which you instantiate the control. You can use that variable only in the method that instantiates the control. The fact that you gave the control a name does not mean that there is a variable defined named txtPassword.
You could continue this way, and dynamically look the control up from any other methods that wish to refer to it. However, that makes life harder than it needs to be. What you really want is a variable that refers to the control.
So, create a private member field of your class named txtPassword. Create the control like this:
txtPassword = new TextBox();
txtPassword.PasswordChar = '*';
....
To be really clear, txtPassword is a private member of your class, not a local variable.
Then you will be able to refer to it from other methods. Is there is a possibility that it might not have been created, test txtPassword against null.
Obviously you use the same technique for any other dynamically created controls.
I think you are mixing something up.
Did you add the controls to the parent form/controls?
Does the event fire ? (put a break point in there)
Try to use them as members instead of the name property and access this.cb and this.tb
You could use your form to find any Child controls that matches your newly created textboxes and Checkboxes.
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.controls(v=vs.110).aspx
Else you could set a reference to this objects in a property on the Form.

How to change icon and text to a ApplicationBarIconButton?

I want to make my click event change an ApplicationBarIconButton. My ApplicationBarIconButton looks like this:
<shell:ApplicationBarIconButton x:Name="driveAction" Click="drive_click" IconUri="/img/car.png" Text="kör" />
I want the IconUri to change from /img/car.png to ex. /img/car-stop.png and the text value from kör to passagera. I tried the function below, but it only causes my app to shut down.
private void drive_click(object sender, EventArgs e)
{
this.driveAction.Text = "passagera";
this.driveAction.Source = "/img/car-stop.png";
}
What is wrong? Why doesn't this work?
The default ApplicationBar requires you to access the buttons through the ApplicationBar object. To accomplish this you must know the index of the button that you want to change
private const int DriveButtonIndex = 0;
private void drive_click(object sender, EventArgs e)
{
var button = (ApplicationBarIconButton)ApplicationBar.Buttons[DriveButtonIndex];
button.IconUri = new Uri("/img/car-stop.png", UriKind.Relative);
button.Text = "passagera";
}
There are a few custom ApplicationBars that allow you to name your buttons. But I've found that the above solution always works for me.
Get it directly from the application bar list -
ApplicationBar.Buttons[0].Text = "passagera";
ApplicationBar.Buttons[0].Source = "/img/car-stop.png";
You could also query the list of buttons for a specific icon as a more tenable long-term solution, but if you only have one button and that's not going to change, this works.
Because the ApplicationBarIconButton is actually a native control and not a true XAML object you cannot refer to it by name.
You can refer to it by index if create in XAML. Alternatively you could create it in code and then you can maintain a named reference you can use.

Categories

Resources