ObjcRuntime.Selector not working on the expected object (xamarin) - c#

I need to respond to the NSStatusBarButton click to show a menu, which unfortunately only has the property "Action" to add a click handler.
The "Action" property requires a selector.
The method I use to handle the click is the following:
[Action("StatusBarClicked:")] public void StatusBarClicked(NSObject sender)
{
// do something
}
And I do the following to assign the button action:
statusBarButton.Action = new Selector("StatusBarClicked:");
Now, it all works when I do this in the DidFinishLaunching method of the app delegate and the StatusBarClicked method is a method of the AppDelegate class.
When I wrap the status bar code in a separate class and declare the method and the selector in that class, it doesn't work (StatusBarClicked is not called).
Strangely enough, if I keep the StatusBarClicked method also in the AppDelegate, that one is called instead:
public class SomeClass
{
public void Test()
{
var statusItem = NSStatusBar
.SystemStatusBar.CreateStatusItem(NSStatusItemLength.Square);
var button = statusItem.Button;
button.Image = NSImage.ImageNamed("test");
button.Action = new Selector("StatusBarClicked:");
}
[Action("StatusBarClicked:")] public void StatusBarClicked(NSObject sender)
{
// never called
}
}
I must be missing something, any idea?

When you set an action the selector is sent to the Target property of the NSControl when the action triggers.
If the target is null the application travels up the responder chain to find the first object that responds to the selector. The app delegate is in the responder chain, that is why that works.
https://developer.apple.com/documentation/appkit/nscontrol/1428885-target?language=objc
If you want to use your custom class as the target I think it needs to subclass NSObject
After you make sure your class extends NSObject you can add this to your constructor:
button.Target = this;

Related

How to execute a method by binding in WPF

A ComboBox and a Button are on different user controls and do not see each other. Both of them are bound to the same ViewModel though.
The Button has a Click event which executes a method in the code-behind of its user control.
I want to be able to execute this method when I change ComboBox. For example let's say the SelectedItem of the ComboBox is bound to a property in ViewModel, now when it is changed, I want the method in the other control to be executed.
You mentioned that these two controls are unaware of one another, but are bound to the same ViewModel. I've found the easiest way to execute some type of code upon a property changing is to execute it directly from the set { } access modifier. Consider the following:
public class MyViewModel
{
private MyObject _currentObject;
public MyObject CurrentObject
{
get { return this._currentObject; }
set
{
this._currentObject = value;
//Usually where OnPropertyChanged goes or however you implement INotifyPropertyChanged
//Where we call our command, logic can be introduced if needed.
//Also we may just call the method directly.
this.SomeCommand.Execute(null);
}
}
private Command _someCommand;
public Command SomeCommand
{
get
{
return this._someCommand ?? (this._someCommand = new Command(
() =>
{
this.SomeMethod();
},
() =>
{
//The CanExecute test, returns bool.
return this._currentObject != null ? true : false;
}));
}
}
private string SomeMethod()
{
return "I just got called yo!";
}
}
Update:
Since the code to execute exists in the handler you will have to do a little work to get this right. Even though this violates MVVM principals it will work:
You will need to move the code to execute to the ViewModel underneath a new method if not already done, let's stick with the SomeMethod() name.
You need to obtain a reference to the ViewModel in the handler. I'm assuming this is already set as the DataContext
MyViewModel viewModel = DataContext as MyViewModel;
Next you will need to call that method from the handler:
viewModel.SomeMethod();
Now you may call the method from the set { } portion of your property contained within the ViewModel.
I hope this works for you.
you would want to create an object (i.e. SelectedComboBoxItem) that raises property changed. then use the generated event to start the event trigger you are trying to create.

Passing open Generic Delegate as Callback

Probably I'm searching for some wrong Keyword, but I couldn't find anything on this matter: I'm tinkering around with WPF MVVM and I'm now at the Point, I'm looking for a solution to give a ViewModel the possibility to request the Container to change to anhother ViewModel.
My approach is to pass a Callback to the created ViewModel, which is held on the Abstract BaseClass and can called, if desired. The method in the Container looks like this:
private void ApplyViewModel<T>()
where T : ViewModelBase
{
_exHandler.HandledAction(
() =>
{
var vm = _viewModelFactory.CreateViewModel<T>();
vm.ApplyViewModel = ApplyViewModel<T>;
CurrentContent = vm;
});
}
The interesting point is the second Line, where I pass the Method itself to the ViewModel.
For this matter, I created also a Delegate:
public delegate void ApplyViewModelDelegate<T>()
where T : ViewModelBase;
The problem lies now in the definition of the Callback in the ViewModelBase: It seems not possible to define it as an open generic Delegate. So I would like to create a Property with the following Signature:
public ApplyViewModelDelegate<T> ApplyViewModel { get; set; }
Is there kindahow a possibility to pass a Delegate as open generic Type, until I'd really like to call it with a specific Type?
Edit:
If I define the Property like this:
public ApplyViewModelDelegate<ViewModelBase> SwitchToViewModel { get; set; }
I can assign the Property from the Container, but my final idea would be to call this Property to target a specific ViewModel. For example, a Command could look like this:
public ViewModelCommand ToTest2
{
get
{
return new ViewModelCommand(
"To Test2",
new ActionCommand(() =>
{
SwitchToViewModel<Test2ViewModel>();
}));
}
}

DialogViewController Missing Back Button

I am using the NavigationItem to drive the navigation of the application. For all of my controllers inheriting from DialogViewController, the back button doesn't show, even if I do
BackButtonBarItem = news UIBarButtonItem(..)
The back button never shows only for dialogs, but does for every other type of controller. Am I missing something?
Use the overloaded DialogViewController constructor
public DialogViewController (RootElement root, bool pushing)
the bool pushing parameter should be true if your DVC is being pushed onto a NavigationController.
use
public YourDialog () : base (UITableViewStyle.Grouped, null, true)
instead of
public YourDialog () : base (UITableViewStyle.Grouped, null)

Return a variable of type assigned in parameters?

I'm trying to create a class like Windows Form, which will have multiple new features. It's simply going to be a "better" version of Form, making my work easier on this exact program. Here's what I have so far:
public class SuperForm : Form
{
protected abstract void OnSizeChanged(object sender, EventArgs e);
public SuperForm()
{
this.SizeChanged += OnSizeChanged;
}
}
Not much, it only makes sure every Form will have to define OnSizeChanged which will be called automatically when size changes, but there's going to be more.
What I need next is a method which takes a class/type as it's parameter and initializes a new object of that type, automatically adds it to Controls and then returns the object. Here's an example code (not working) on how I would like it to be like:
public cls NewControl(ClassType cls) // This obviously doesn't work.
// I need it to return an object of type "cls" parameter.
{
cls newControl = new cls();
this.Controls.Add(newControl);
return newControl;
}
I know ClassType is not a valid type, that's why I need help.
And then I could basically call it like this:
Button b = this.NewControl(Button);
Which would return a new button and also add it to this.Controls. I might eventually need to do more of these common tasks when a control is initialized, so that's why I'd like to have it in it's own method.
Is this possible in C#? If not, are there any workarounds? One way would be to define a method for each class inheriting from Control like this:
public Button NewControl(Button b);
public TextBox NewControl(TextBox tb);
public ListBox NewControl(ListBox lb);
But it doesn't seem like a valid option to me.
It sounds like you want to make a generic method, with a couple of constraints on the type parameter:
public T CreateAndAdd<T>() where T : Control, new()
{
T newControl = new T();
Controls.Add(newControl);
return newControl;
}
Here the T : Control constraint makes sure that you're creating a control, so that you'll be able to use Controls.Add. The T : new() constraint makes sure the type argument has a public parameterless constructor, so that you can call new T().
To create a TextBox, for example, you would call the function like this:
var tb = CreateAndAdd<TextBox>()
(I've renamed the method for what I believe to be clarity, btw.)

c# Forms Project: Passing Information to User Control

I have created a forms application which uses a TabControl. For each tab I want to place a single UserControl (created in the same project) which contains all the other controls. However, I will need to pass some information from the primary form to the UserControl for it to work property with events, methods, etc. How can/should I do this?
I tried creating a constructor with parameters but then Designer fails and I have to go in and delete out the added UserControl references.
Thanks!
The constructor parameter is the correct method. However, there must still be a default constructor in order for the Designer to be able to construct (and draw) a copy of the object.
My usual workaround is to put a clause in the default constructor, checking to see that we are in "design mode" and throwing an exception if not:
public class MyForm: Form
{
public MyForm()
{
if(!DesignMode) throw new InvalidOperationException("Cannot use default constructor in production code");
}
public MyForm(MyDependency dependent)
{
...
}
}
you can pass information by a function that created in usercontrol.cs file.
for example in usercontrol.cs
public string name;
public void SetName(string pname)
{
this.name = pname;
}
or maybe you want to change button name
Button mybutton = new Button();
public void SetButtonName(string btname)
{
this.mybutton.Text = btname;
}
Now you can call these functions in your mainform.cs
Myusercontrol usc = new Myusercontrol();
usc.SetName("this is string for 'name' string");
usc.SetButtonName("this is string for button text");
Try creating your constructor, but also creating a default parameterless constructor.
Take a look at this question

Categories