0

I am trying to add and then remove custom MouseClick event handlers to some Buttons. The controls on the window are being built at run-time. I can add my custom handler as per another answered question. localBtn.MouseClick += new MouseEventHandler((se, e) => Move_MouseClick(se, e, center, type));

I read the other questions about remove EventHandlers, but they seem to geared to the 'standard' event handler. I finally got this to compile object se=null; MouseEventArgs e=null; localBtn.MouseClick -= new MouseEventHandler((se1, e1) => Move_MouseClick( se, e, center, type)); (Where center and type are passed in parameters.) I do not know if this works or not...as I have run out of time for today....

I'm creating a grid (8x4) of buttons (maybe larger in the future), when one is clicked, the surrounding buttons 'change' into action buttons. Think of tic-tac-toe and the center button is the one clicked, all the others become 'active'. The custom handler is created with a reference to the 'center' button and then an enum indicating which of the 8 buttons then handler is for, top,left,right, topLeft, BottomRight, etc.. Once one of the 'active' buttons is pressed 'something happens' and the handlers need to be removed and the buttons will revert to their 'inactive' state. The buttons are derived from an object that has 'references' to all the other 'buttons' around it.

I read How to remove all event handlers from a control and C# removing an event handlerr.

Perhaps a better control is more suited to what I'm doing ?

[edit] I have tried the -= as shown above but that did not work. The control still had both event handlers attached. The program did not fail in anyway, so I'm not sure what the -= did? I guess nothing.

Community
  • 1
  • 1
Ryan Buton
  • 341
  • 3
  • 11
  • It really sounds like a user control is what you want. – Daniel Ward Jun 04 '14 at 22:51
  • Not sure what the 'custom control' would replace. Since any button could be selected as the 'center' and any button could be considered a neighbor. I guess each button would be a custom control and I would set a property for each neighbor button so when the MouseClick occurred it would 'know' it relationship to the clicked button, since the relationship would change. – Ryan Buton Jun 05 '14 at 16:03
  • User controls inherit from Control, so it would not be able to inherit Button, so it would not be a button. User controls don't replace a control, they replace multiple controls that serve a single task (like the color picker seen [here](http://wpftutorial.net/CustomVsUserControl.html), for example). I think [this](http://www.codeproject.com/Articles/179442/So-what-s-the-difference-between-a-Custom-Control) gives a good, quick rundown of the difference between the two. – Daniel Ward Jun 05 '14 at 16:20
  • Also, I got that backwards: user controls inherit from UserControl, and custom controls inherit from Control (which means they can inherit from things like Button and TextBox) – Daniel Ward Jun 05 '14 at 16:28

2 Answers2

2

It sounds like you should use a user control for what you're trying to accomplish. Here is an example of how it could be done in code behind (there may be a better way for what you're doing specifically; this is just to give you a working example):

ButtonGrid.xaml:

<UserControl x:Class="WpfApplication1.ButtonGrid"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid x:Name="PART_Grid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
    </Grid>
</UserControl>

ButtonGrid.cs (could also make the Grid in here, since everything else is being done in here):

public partial class ButtonGrid : UserControl
    {
        private int rows, cols;
        private Button[] buttons;
        public ButtonGrid()
        {
            InitializeComponent();

            cols = 4;
            rows = 8;
            buttons = new Button[cols * rows];
            Button button;
            for (int i = 0; i < cols; i++)
            {
                for (int j = 0; j < rows; j++)
                {
                    // Make the button, set its place on the grid, set the necessary properties, give it OnClick, then add it to the grid
                    button = new Button();
                    button.SetValue(Grid.ColumnProperty, i);
                    button.SetValue(Grid.RowProperty, j);

                    button.Name = "Button" + (j + (rows * (i))).ToString();
                    button.Content = j + (rows * (i));
                    button.IsEnabled = false;

                    button.Click += OnClick;

                    buttons[j + (rows * (i))] = button;
                    PART_Grid.Children.Add(button);
                }
            }
            buttons[12].IsEnabled = true;
        }

        private void OnClick(object sender, RoutedEventArgs e)
        {
            int index;
            Button button = sender as Button;
            // Determine which button was pressed by finding the index of the button that called this from the button name
            if (button.Name.Length == 7)
            {
                index = Int32.Parse(button.Name.Substring(6, 1));
            }
            else
            {
                index = Int32.Parse(button.Name.Substring(6, 2));
            }

            // Make sure the buttons that are being affected are within bounds
            if ((index - 1) >= 0)
            {
                buttons[index - 1].IsEnabled = true;
            }

            if ((index - rows) >= 0)
            {
                buttons[index - rows].IsEnabled = true;
            }

            if ((index + 1) <= (cols * rows - 1))
            {
                buttons[index + 1].IsEnabled = true;
            }

            if ((index + rows) <= (cols * rows - 1))
            {
                buttons[index + rows].IsEnabled = true;
            }
        }
    }

I just put it in the main window with <local:ButtonGrid Width="500" Height="500" />.

enter code here

And when pressed:

enter image description here

And you can keep clicking the buttons to see how the ones around it become enabled (or whatever you want to happen to them).

Daniel Ward
  • 274
  • 2
  • 12
  • Very nice! I'm using WinForms and have never tried WPF, so not sure how much applies. I had wanted to stay away from array indices and to use pointers (references) to these items, but that might be making my job harder than it is worth. So given your example, when I press the '20' something will happen to the '12' cell. When the '12' cell is press again, all the cell will be enabled, waiting for a new center to be pressed. So the event has to 'know' am I being pressed to select the center or to change the center. So I thought adding and removing events would be an easy way to do this. – Ryan Buton Jun 05 '14 at 16:18
  • I am not sure how much Forms differs, either, to be honest, but my impression is that what can be done in one can be done similarly in the other. What do you mean when you say, "When the '12' cell is press again, all the cell will be enabled, waiting for a new center to be pressed."? – Daniel Ward Jun 05 '14 at 16:24
  • The idea is that the user will do 'something' to say cell '12', then when complete they will do 'something' to cell '22'. What I'm trying to come up with is a simple UI page layout tool. Each cell represents a type of UI display element. Once selected, by pressing the other nearby buttons, the user can move, enlarge or shrink the display element. I can only use click events as there's only the touch screen. I know you can drag on a touch but the users are not always able to hold down on the screen in a continuous manner. This way the end user can change the layout of the screen. ok? – Ryan Buton Jun 05 '14 at 19:08
  • "When the '12' cell is press again, all the cell will be enabled, waiting for a new center to be pressed."? ... Maybe I just left out the word 'other' as in '... all the other cells will'... – Ryan Buton Jun 05 '14 at 19:08
  • I am not sure why you want to use pointers for this. Anyway, this was only to show you a working example - the point is that, through that OnClick method, you can 1) access all of the buttons and 2) determine which button was clicked. You can manipulate the entire control however you like from there. Isn't that what you need? – Daniel Ward Jun 05 '14 at 19:11
  • You're right, I'm just not that comfortable with C#, so I revert back to C's 'do everything with pointers' type thinking. I did not think about placing the 'Id' in the 'name' field and then using that as 'pointer' of sorts. – Ryan Buton Jun 05 '14 at 19:55
  • There may be a better way to access each individual button (maybe [this](http://msdn.microsoft.com/en-us/library/7w3e62a8(v=vs.110).aspx)?), but I usually access them with their name in WPF. Investigate that if you think there may be a better way to do it. Also, please accept the answer (not just upvote) if it answered your question. – Daniel Ward Jun 05 '14 at 20:24
  • The original question was 'how to remove a custom event handler'. Your answer, which I thought was very helpful, only provided a work around or different approach. So I upVoted indicating I appreciated your effort, but did not select it as an answer since it did not answer the original question. If someone else was searching for "how to remove a custom event handler", your answer might not fit whatever they were doing. I guess if the answer is "You can not remove a custom event handler. You must do it a different way." Then yes you did answer the question. – Ryan Buton Jun 11 '14 at 15:37
0

you can create another on mouseclick event empty and assign your button's click to that empty button,

but this time dont use += , just use =

Mike
  • 789
  • 8
  • 15
  • ok, I guess. But it removes all other events. But I would think that if you can += something you could -= it. Otherwise it appears that you can only add custom events but never remove them? Seems weird. – Ryan Buton Jun 05 '14 at 15:26