简体   繁体   中英

How to create an event for custom control

I have created a custom control(list) with an image, 2 labels and a button. I want to invoke button click of the custom control. My whole control will also have a separate event. 在此处输入图片说明

Here is my usercontrol tamplate code:

namespace __
{
    public class SelectMultipleBasePage<T> : ContentPage
    {

        public class WrappedSelection<T> : INotifyPropertyChanged
        {
            public T Item { get; set; }
            bool isSelected = false;
            public bool IsSelected
            {
                get
                {
                    return isSelected;
                }
                set
                {
                    if (isSelected != value)
                    {
                        isSelected = value;
                        PropertyChanged(this, new PropertyChangedEventArgs("IsSelected"));
                        //                      PropertyChanged (this, new PropertyChangedEventArgs (nameof (IsSelected))); // C# 6
                    }
                }
            }
            public event PropertyChangedEventHandler PropertyChanged = delegate { };
        }
        public class BackGroundColorConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                if (value is bool)
                {
                    if ((bool)value)
                    {
                        return Color.FromHex("#DEE4EA");
                    }
                    else
                    {
                        return Color.White;
                    }
                }
                else
                {
                    return Color.White;
                }
            }

            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                throw new NotImplementedException();
            }

        }

        public class WrappedItemSelectionTemplate : ViewCell
        {
             static int i=0; // don't forget to make it static 
            public WrappedItemSelectionTemplate()
                : base()
             {

                 var items = RecordingListPage.items;
                 Grid objGrid = new Grid();
                 objGrid.RowDefinitions.Add(new RowDefinition
                 {
                     Height = new GridLength(1, GridUnitType.Star)
                 });
                 objGrid.ColumnDefinitions.Add(new ColumnDefinition
                 {
                     Width = new GridLength(75, GridUnitType.Absolute),
                 });
                 objGrid.ColumnDefinitions.Add(new ColumnDefinition
                 {
                     Width = new GridLength(1, GridUnitType.Star)
                 });
                 objGrid.ColumnDefinitions.Add(new ColumnDefinition
                 {
                     Width = new GridLength(75, GridUnitType.Absolute),
                 });

                 // Column 1:-
                 Image objImage = new Image();
                 objImage.SetBinding(Image.SourceProperty, new Binding("Item.Image"));
                 objGrid.Children.Add(objImage, 0, 0);
                 // Column 2:-
                 StackLayout objStackLayoutCol2 = new StackLayout();
                 objGrid.Children.Add(objStackLayoutCol2, 1, 0);

                 Label name = new Label()
                 {
                     Text = "Name",
                     Style = (Style)Application.Current.Resources["LabelStyle"],
                 };
                 Label date = new Label()
                 {
                     Text = "Date",
                     Style = (Style)Application.Current.Resources["LabelStyleTiny"]
                 };
                 name.SetBinding(Label.TextProperty, new Binding("Item.Name"));
                 date.SetBinding(Label.TextProperty, new Binding("Item.Date"));
                 objStackLayoutCol2.Children.Add(name);
                 objStackLayoutCol2.Children.Add(date);
                 objStackLayoutCol2.Padding = new Thickness(10);

                 Label objImageView = new Label();
                 objImageView.Text = FontAwesome.FAPencilSquareO;
                 objImageView.FontSize = 35;
                 objImageView.VerticalOptions = LayoutOptions.CenterAndExpand;
                 objImageView.HorizontalOptions = LayoutOptions.CenterAndExpand;
                 objImageView.TextColor = Color.Black;

                 StackLayout stv = new StackLayout();
                 stv.Children.Add(objImageView);
                 stv.Padding = new Thickness(10);
                 stv.HorizontalOptions = LayoutOptions.Center;
                 stv.VerticalOptions = LayoutOptions.Center;

                 objImageView.StyleId = items[i].Id.ToString();
                 i++;
                 if (i == items.Count)
                 {
                     i = 0;
                 }

                 var tapGestureRecognizer = new TapGestureRecognizer();
                  tapGestureRecognizer.Tapped += OnImageBtnTapped;
                 objImageView.GestureRecognizers.Add(tapGestureRecognizer);

                 objGrid.Children.Add(stv, 2, 0);

                 var moreAction = new MenuItem { Text = "More" };

                 moreAction.SetBinding(MenuItem.CommandParameterProperty, new Binding("."));
                 moreAction.Clicked += (sender, e) =>
                 {
                     var mi = ((MenuItem)sender);
                     //Debug.WriteLine("More Context Action clicked: " + mi.CommandParameter);
                 };

                 var deleteAction = new MenuItem { Text = "Delete", IsDestructive = true }; // red background
                 deleteAction.Icon = Device.OnPlatform("Icons/cancel.png", "cancel.png", "Images/cancel.png");
                 deleteAction.SetBinding(MenuItem.CommandParameterProperty, new Binding("."));
                 deleteAction.Clicked += (sender, e) =>
                 {
                     var mi = ((MenuItem)sender);
                     //Debug.WriteLine("Delete Context Action clicked: " + mi.CommandParameter);
                 };

                 //
                 // add context actions to the cell
                 //
                 ContextActions.Add(moreAction);
                 ContextActions.Add(deleteAction);
                 //objGrid.Padding = new Thickness(10);

                 StackLayout st = new StackLayout();
                 st.Children.Add(objGrid);
                 st.Children.Add(new BoxView() { Color = Color.FromHex("#A4B3C1"), WidthRequest = 100, HeightRequest = 1 });


                 View = st;


             }

            private void OnImageBtnTapped(object sender, EventArgs e)
            {
                var tappedImage = (Label)sender;
                var ImageId = Convert.ToInt32(tappedImage.StyleId);
                Application.Current.Properties["ItemId"] = ImageId;
                MessagingCenter.Send(new RedirectClass.OpenRecordingDetails(), RedirectClass.OpenRecordingDetails.Key);
            }

        }
        public static List<WrappedSelection<T>> WrappedItems = new List<WrappedSelection<T>>();
        public SelectMultipleBasePage(List<T> items)
        {
            WrappedItems = items.Select(item => new WrappedSelection<T>() { Item = item, IsSelected = false }).ToList();
            ListView mainList = new ListView()
            {
                ItemsSource = WrappedItems,
                ItemTemplate = new DataTemplate(typeof(WrappedItemSelectionTemplate)),
            };

            mainList.ItemSelected += (sender, e) =>
            {
                if (e.SelectedItem == null) return;
                var o = (WrappedSelection<T>)e.SelectedItem;
                o.IsSelected = !o.IsSelected;
                ((ListView)sender).SelectedItem = null; //de-select
            };
            Content = mainList;
            mainList.HasUnevenRows = true;


            if (Device.OS == TargetPlatform.WinPhone)
            {   // fix issue where rows are badly sized (as tall as the screen) on WinPhone8.1
                mainList.RowHeight = 40;
                // also need icons for Windows app bar (other platforms can just use text)
                ToolbarItems.Add(new ToolbarItem("All", "check.png", SelectAll, ToolbarItemOrder.Primary));
                ToolbarItems.Add(new ToolbarItem("None", "cancel.png", SelectNone, ToolbarItemOrder.Primary));
            }
            else
            {
                ToolbarItems.Add(new ToolbarItem("All", null, SelectAll, ToolbarItemOrder.Primary));
                ToolbarItems.Add(new ToolbarItem("None", null, SelectNone, ToolbarItemOrder.Primary));
            }
        }
        void SelectAll()
        {
            foreach (var wi in WrappedItems)
            {
                wi.IsSelected = true;
            }
        }
        void SelectNone()
        {
            foreach (var wi in WrappedItems)
            {
                wi.IsSelected = false;
            }
        }
        public static List<T> GetSelection()
        {
            return WrappedItems.Where(item => item.IsSelected).Select(wrappedItem => wrappedItem.Item).ToList();
        }
    }
}

I have an event OnImageBtnTapped which I want to access from my content page. How can I do that?

EDIT

Thanks to @Jason, I managed to get event click function in the code that is using the control.

In the custom control class:

private void OnImageBtnTapped(object sender, EventArgs e)
{
   if (OnImageSelected != null) 
   {
        OnImageSelected(sender,e);
   }
}

In the code that is using the control,

SelectMultipleBasePage<ListItems>.OnImageSelected += ListPage_OnImageSelected;

void ListPage_OnImageSelected(object sender, EventArgs e)
{

    var tappedImage = (Label)sender;
    var ImageId = Convert.ToInt32(tappedImage.StyleId);

    Application.Current.Properties["ItemId"] = ImageId;

    MessagingCenter.Send(new RedirectClass.OpenRecordingDetails(), RedirectClass.OpenRecordingDetails.Key);
}

this is no different than creating a custom event for any C# code

First, create a public event and handler in your class:

// note: you may want to create your own ImageEventArgs class that inherits from EventArgs
public delegate void ImageSelectedHandler(object sender, EventArgs e);
public event ImageSelectedHandler OnImageSelected;

next, inside the control you can call the handler if it exists

private void OnImageBtnTapped(object sender, EventArgs e)
{
  var tappedImage = (Label)sender;
  var ImageId = Convert.ToInt32(tappedImage.StyleId);
  Application.Current.Properties["ItemId"] = ImageId;

  MessagingCenter.Send(new RedirectClass.OpenRecordingDetails(), RedirectClass.OpenRecordingDetails.Key);

  // check if a handler is assigned
  if (OnImageSelected != null) {
    OnImageSelected(this,new EventArgs(...));
  }
}

finally, in the code that is using the control, just define an event handler like you normally would

myControl.OnImageSelected += delegate {
  // handler logic goes here
};

You can hand over the handler from the parent to the child. Then it involves no static event handlers. You just have to add a parameter to your WrappedItemSelectionTemplate and create your template using new DataTemplate(() => new WrappedItemSelectionTemplate(HandleImageSelected)) .

public class SelectMultipleBasePage<T> : ContentPage
{
    public delegate void ImageSelectedHandler(object sender, EventArgs e);
    public event ImageSelectedHandler OnImageSelected;

    public class WrappedItemSelectionTemplate : ViewCell
    {
        private readonly ImageSelectedHandler _parentHandler;
        public WrappedItemSelectionTemplate(ImageSelectedHandler parentHandler)
            : base()
        {
            _parentHandler = parentHandler;

            // ...
            View = st;
        }

        private void OnImageBtnTapped(object sender, EventArgs e)
        {
            //...
            _parentHandler.Invoke(sender, e);
        }

    }
    public static List<WrappedSelection<T>> WrappedItems = new List<WrappedSelection<T>>();
    public SelectMultipleBasePage(List<T> items)
    {
        WrappedItems = items.Select(item => new WrappedSelection<T>() { Item = item, IsSelected = false }).ToList();
        ListView mainList = new ListView()
        {
            ItemsSource = WrappedItems,
            ItemTemplate = new DataTemplate(() => new WrappedItemSelectionTemplate(HandleImageSelected)),
        };
        // ...
    }

    private void HandleImageSelected(object sender, EventArgs e)
    {
        if (OnImageSelected != null)
        {
            OnImageSelected(sender, e);
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM