How to pass callback method from xaml? (Xamarin.form & WPF) - c#

I'm making my custom image button on Xamarin form.
But below my code is not working.
runtime error message :
Position 26:34. Cannot assign property "buttonCallback": type mismatch between "System.String" and "XXX.CircleImageButton+ClickedDelegate"
What's the right way to pass callback method from xaml?
And How do you call that technique?
Thanks.
myxaml.xaml
<local:CircleImageButton buttonCallback="buttonCallback"...
myxaml.xaml.cs
void buttonCallback()
{
...
}
CircleImageButton.cs
using System;
using ImageCircle.Forms.Plugin.Abstractions;
using Xamarin.Forms;
namespace XXX
{
public class CircleImageButton : CircleImage
{
public delegate void ClickedDelegate();
public ClickedDelegate buttonCallback { set; get; }
public CircleImageButton ()
{
this.GestureRecognizers.Add (new TapGestureRecognizer{
Command = new Command(() => {
this.Opacity = 0.6;
this.FadeTo(1);
this.buttonCallback();
})
});
}
}
}

Just change your code to:
public event ClickedDelegate buttonCallback;
Suggestion
For custom events, I'd use this structure:
MyBarElement
Decalaration
public event EventHandler FooHappend;
Invocation
FooHappend?.Invoke(this, EventArgs.Empty);
Page
Then you can use
<MyBarElement FooHappend="OnFooHappend"></MyBarElement>
In your code behind
private void OnFooHappend(object sender, EventArgs eventArgs)
{
}

A brief addition to Sven's answer (as I am not yet allowed to comment); if you wish to use custom EventArgs in order to pass back customizable information, you must use:
public event EventHandler<CustomEventArgs> FooHappend;
along with:
FooHappend?.Invoke(this, new CustomEventArgs(MyValue.ToString()));
and:
private void OnFooHappend(object sender, CustomEventArgs eventArgs)
{
}
which you can easily define like so:
public class CustomEventArgs: EventArgs
{
private readonly string customString;
public CustomEventArgs(string customString)
{
this.customString= customString;
}
public string CustomString
{
get { return this.customString; }
}
}
Hope this saves someone an hour or two down the road :)

Related

MAUI Handler Xaml to Platform Connection

I am using the handler feature of MAUI, but the methods in the platform specific classes are not being called.
This is the click event for the xaml page:
private void ActivateCamera(object sender, EventArgs e)
{
cameraView.MakePhoto();
}
This are the Interface and the View classes:
public interface ICameraView : IView
{
void MakePhoto();
}
public class CameraView : View, ICameraView
{
CameraViewHandler StrongHandler => Handler as CameraViewHandler;
public void MakePhoto() => StrongHandler?.Invoke(nameof(MakePhoto), null);
}
This is the Handler:
public class CameraViewHandler : ViewHandler<ICameraView, NativePlatformCameraPreviewView>
{
public static CommandMapper<ICameraView, CameraViewHandler> CameraCommandMapper = new()
{
[nameof(ICameraView.MakePhoto)] = MapMakePhoto
};
public static void MapMakePhoto(CameraViewHandler handler, ICameraView cameraView, object? parameter)
=> handler.TakePhoto();
public void TakePhoto() => _cameraController?.TakePicture();
// The TakePicture method is implemented in the iOS and android files, but as said, is not being executed
}
I have this in MauiProgramm:
handlers.AddHandler(typeof(CameraView), typeof(CameraViewHandler));
Can someone see why this is not working?
Did you check the official document about creating a custom control using handlers? The mapped method should in the platform custom handler class.
So CameraViewHandler.cs should be such as:
public partial class CameraViewHandler : ViewHandler<ICameraView, NativePlatformCameraPreviewView>
{
public static CommandMapper<ICameraView, CameraViewHandler> CameraCommandMapper = new()
{
[nameof(ICameraView.MakePhoto)] = MapMakePhoto
};
}
And the MapMakePhoto method in the CameraViewHandler.Android.cs:
public static void MapMakePhoto(CameraViewHandler handler, ICameraView cameraView)
{
handler.PlatformView?.NativeMethod();
}
For more information, you can refer to the official sample on the github about the handlers.
Update
Don't forget the construction method of the handler:
public CameraViewHandler() : base(CameraViewMapper, CameraCommandMapper) { }

How to create events and proper use of event handlers for a button click C#

I'm fairly new to C# and I'm trying to create a Hangman game in WinForms, I've got the game functionality working, but I'm trying to create a form where the user selects a category and then the word to guess is from the category selected.
I've got a HangEventArgs like below:
public class HangEventArgs : EventArgs
{
public Category WordCategory { get; set; }
}
and a class for the data (I'm hoping to expand it to add more features in the future).
public enum Category
{
// Categories are stores here
}
public class HangData
{
public Category WordCategory { get; protected set; }
public HangData(Category askWhat)
{
WordCategory = askWhat;
}
}
And a class where the words are stored
public static class WordsToGuess
{
public static string[] Capitals =
{
"London",
"Paris" // more words here
}; // more categories here
Finally I have my button click event for all the categories, I've created my own Button as to not use the default EventArgs.
private void bCategory_Click(object sender, HangEventArgs e)
{
MainGame mg = new MainGame(new HangData(e.WordCategory));
mg.ShowDialog();
}
I've been trying to use event handlers like so
public event EventHandler<HangEventArgs>(object sender, HangEventArgs e);
But I'm not sure the proper way to implement this into my code.
If I use
bCapitals.Click += new EventHandler(bCategory_Click);
I get a no overload matches delegate error and I'm stuck on how to fix it. Thanks for the help in advance.
Create your category button like this:
public class CategoryButton : Button
{
protected override void OnClick(EventArgs e)
{
// Just discard the `e` argument and pass your own argument.
base.OnClick(new HangEventArgs { WordCategory = Category.Cities });
}
}
Subscribe the event with:
categoryButton1.Click += CategoryButton1_Click;
Use like this
private void CategoryButton1_Click(object sender, EventArgs e)
{
if (e is HangEventArgs hangEventArgs) {
MessageBox.Show(hangEventArgs.WordCategory.ToString());
}
}
Note that the click mechanism still works as expected. You don't need to fire the event yourself.
Of course you could create your own event; however, then, it must have a different name like HangClick and you must fire it yourself.
public class CategoryButton : Button
{
public event EventHandler<HangEventArgs> HangClick;
protected virtual void OnHangClick(HangEventArgs e)
{
HangClick?.Invoke(this, e);
}
protected override void OnClick(EventArgs e)
{
OnHangClick(new HangEventArgs { WordCategory = Category.Cities });
// Optionally, if you want to preserve the standard click event behaviour:
base.OnClick(e);
}
}
Subscribe with:
categoryButton1.HangClick += CategoryButton1_HangClick;
Use like this:
private void CategoryButton1_HangClick(object sender, HangEventArgs e)
{
MessageBox.Show(e.WordCategory.ToString());
}

how do i set a userControl function's action from its parent form?

I have a userControl function that i want to set its action from the parent form.
I've already set userControl button action from that parent form.
and it worked like this :
in Form1.cs :
public Form1()
{
InitializeComponent();
fileManagerLocal1.SetSendButton(SendMethod);
}
private void SendMethod()
{
//whatever ...
}
in userControl1.cs :
public void SetSendButton(Action action)
{
btnSend.Click += (s, e) => action();
}
the code up works great.
but what i need is how do i set a Function action ..
in Form1.cs
public Form1()
{
InitializeComponent();
fileTransfer1.RefreshLocalFM(RefreshFM);
}
public void RefreshFM()
{
fileManagerLocal1.btnRefresh.PerformClick();
}
in userControl1.cs
public void RefreshLocalFM(Action action)
{
action(); // what should be in here ?
}
thanks in advance. :)
It's not clear to me what you mean by "set a Function action".
Do you want to call that function immediately within the context of the controller? in that case the code you provided is correct.
If on the other hand you want to configure the user control to use the provided action in some later code, then you need to store that Action as follows
in userControl1
Action externalFunction = null;
public void RefreshLocalFM(Action action)
{
externalFunction = action;
}
// later code
private void someMethod()
{
externalFunction();
}
I hope I understood you correctly..
I've figured it out a solution ..
in Form1.cs :
public Form1()
{
InitializeComponent();
fileTransfer1.refreshAction = new Action (RefreshFM);
//let's say refreshAction is a public action variable in fileTransfer1 class
}
public void RefreshFM()
{
fileManagerLocal1.btnRefresh.PerformClick();
}
in userControl1.cs:
public Action refreshAction;
//then it can be called from any place.
private void RefreshLocalFM()
{
refreshAction.Invoke(); //this fires the action that we initialized from form1.cs
}

Issue with putting Command CanExecute and Executed handlers out of the main window class

Basically I've got a command binding for the command itself assigned to Window.CommandBindings:
<CommandBinding Command="local:TimerViewModel.AddTimer"
CanExecute="local:TimerViewModel.AddTimer_CanExecute"
Executed="local:TimerViewModel.AddTimer_Executed" />
local is a namespace generated by default pointing to the namespace of the application. What I'm trying to achieve here is to have the command handling inside the TimerViewModel but I keep getting the following error:
CanExecute="local:TimerViewModel.AddTimer_CanExecute" is not valid. 'local:TimerViewModel.AddTimer_CanExecute' is not a valid event handler method name. Only instance methods on the generated or code-behind class are valid.
The TimerViewModel is pretty simple though but I believe I am missing something:
public class TimerViewModel : ViewModelBase
{
public TimerViewModel()
{
_timers = new ObservableCollection<TimerModel>();
_addTimer = new RoutedUICommand("Add Timer", "AddTimer", GetType());
}
private ObservableCollection<TimerModel> _timers;
public ObservableCollection<TimerModel> Timers
{
get { return _timers; }
}
private static RoutedUICommand _addTimer;
public static RoutedUICommand AddTimer
{
get { return _addTimer; }
}
public void AddTimer_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
public void AddTimer_Executed(object sender, ExecutedRoutedEventArgs e)
{
_timers.Add(new TimerModel(TimeSpan.FromSeconds((new Random()).Next())));
}
}
Can anyone point out the mistakes I'm making?
Also take a look at Josh Smith's RelayCommand. Using it would enable you to write the above like this:
public class TimerViewModel : ViewModelBase {
public TimerViewModel() {
Timers = new ObservableCollection<TimerModel>();
AddTimerCommand = new RelayCommand(() => AddTimer());
}
public ObservableCollection<TimerModel> Timers {
get;
private set;
}
public ICommand AddTimerCommand {
get;
private set;
}
private void AddTimer() {
Timers.Add(new TimerModel(TimeSpan.FromSeconds((new Random()).Next())));
}
}
Take a look at http://www.wpftutorial.net/DelegateCommand.html for an example of how to implement the delegate command for WPF. It allows you to hook up Execute and CanExecute as event handlers. If you're using RoutedUICommand directly you need to derive a custom command from it and override Execute and CanExecute with your functions.

.NET Collections and Accessing Object Methods

I'm completely new to GUI programming and need a little help with a list of pictureboxes.
The idea is that I have a list of pictureboxes. When a user clicks on one I want to (for example) change the BorderStyle property of the one selected to be Fixed3D, but change the remaining collection borders to FixedSingle (or something like that). What's the proper way to do something like this? I guess the bigger picture is how do I get a method of one class to call a method of another without having any information about it?
class myPicture
{
private int _pictureNumber;
private PictureBox _box;
public myPicture(int order)
{
_box = new List<PictureBox>();
_box.Click += new System.EventHandler(box_click);
_pictureNumber = order;
}
public void setBorderStyle(BorderStyle bs)
{
_box.BorderStyle = bs;
}
public void box_click(object sender, EventArgs e)
{
//here I'd like to call the set_borders from myPicturesContainer, but I don't know or have any knowledge of the instantiation
}
}
class myPicturesContainer
{
private List<myPicture> _myPictures;
//constructor and other code omitted, not really needed...
public void set_borders(int i)
{
foreach(myPicture mp in _MyPictures)
mp.setBorderStyle(BorderStyle.FixedSingle);
if(i>0 && _MyPictures.Count>=i)
_MyPictures[i].setBorderStyle(BorderStyle.Fixed3d);
}
}
You will need to create a Clicked event in your myPicture class and raise that event when it is clicked. Then you will need to attach to this event in your myPicturesContainer for each instance of myPicture that you have.
Here is a very simple example of what I mean:
class myPicture
{
public event Action<Int32> Clicked = delegate { };
private int _pictureNumber;
public void box_click(object sender, EventArgs e)
{
this.Clicked(this._pictureNumber);
}
}
class myPicturesContainer
{
private List<myPicture> _myPictures;
public void set_borders(int i)
{
foreach (myPicture mp in _myPictures)
{
mp.Clicked += pictureClick;
}
}
void pictureClick(Int32 pictureId)
{
// This method will be called and the pictureId
// of the clicked picture will be passed in
}
}

Categories