简体   繁体   中英

Capture Click Event of generic button in a derrived Class

I'm working on a WPF app, where most of the controls are created dynamically at runtime. To save some code, I've created various static controls. Now, I want to create a textbox control with a delete button next to it. The point where I'm stuck now is, how do I capture events of the controls? (see code)

Edit: As suggested I tried to create a custom control. However, I can't get the custom event working. Ie in the wpf-page I can't find the delete Event to hook a handler to it. Where did I go wrong? So far I found out, that when I drop the : Grid statement, the Event is shown.

  public class tbTextReadOnlyWithDeleteButton : Grid
{

    public event EventHandler Delete;

    public tbTextReadOnlyWithDeleteButton(int gridrow, int gridcol, string feldname, object quelle, string ctlname, object tag)
    {
        Grid gr = new Grid() { Name = "grMit_" + gridrow + "_" + gridcol + "_" + ctlname };
        gr.SetValue(Grid.RowProperty, gridrow);
        gr.SetValue(Grid.ColumnProperty, gridcol);
        gr.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(30) });
        gr.ColumnDefinitions.Add(new ColumnDefinition());
        gr.Tag = tag;


        Button bu = new Button() { Name = "buLoeschen" };
        bu.SetValue(Grid.ColumnProperty, 0);
        bu.Margin = new Thickness(5, 5, 5, 5);
        bu.Content = "\xE10A";
        bu.FontFamily = new FontFamily("Segoe MDL2 Assets");
        bu.FontSize = 10;
        bu.Tag = quelle;
        bu.Click += Bu_Click;


        TextBox tb = new TextBox();
        tb.SetValue(Grid.RowProperty, 0);
        tb.SetValue(Grid.ColumnProperty, 1);
        tb.IsReadOnly = true;
        tb.VerticalContentAlignment = VerticalAlignment.Center;
        tb.HorizontalContentAlignment = HorizontalAlignment.Left;
        tb.Background = new SolidColorBrush() { Opacity = 1 };
        tb.BorderThickness = new Thickness(0);
        tb.TextWrapping = TextWrapping.Wrap;
        BindingOperations.SetBinding(tb, TextBox.TextProperty, new Binding(feldname) { Source = quelle, Mode = BindingMode.OneWay });

        gr.Children.Add(bu);
        gr.Children.Add(tb);


    }

    private void Bu_Click(object sender, RoutedEventArgs e)
    {
        Delete(sender, e);
    }
}

// in the page it looks like this:
Grid tbMit = new tbTextReadOnlyWithDeleteButton(1, 0, "Name", mit, "name", dat);

tbMit.Delete // <-- Why can't this be found??

End Edit

    // Control
    public static Grid tbTextReadOnlyWithDeleteButton(int gridrow, int gridcol, string feldname, object quelle)
    {
        Grid gr = new Grid();
        gr.SetValue(Grid.RowProperty, gridrow);
        gr.SetValue(Grid.ColumnProperty, gridcol);
        gr.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(30)});
        gr.ColumnDefinitions.Add(new ColumnDefinition());


        Button bu = new Button() { Name = "buDelete" };
        bu.SetValue(Grid.ColumnProperty, 0);
        bu.Margin = new Thickness(5, 5, 5, 5);
        bu.Content = "\xE10A";
        bu.FontFamily = new FontFamily("Segoe MDL2 Assets");
        bu.FontSize = 10;
        bu.Tag = quelle;


        TextBox tb = new TextBox();
        tb.SetValue(Grid.RowProperty, 0);
        tb.SetValue(Grid.ColumnProperty, 1);
        tb.IsReadOnly = true;
        tb.VerticalContentAlignment = VerticalAlignment.Center;
        tb.HorizontalContentAlignment = HorizontalAlignment.Left;
        tb.Background = new SolidColorBrush() { Opacity = 1 };
        tb.BorderThickness = new Thickness(0);
        tb.TextWrapping = TextWrapping.Wrap;
        BindingOperations.SetBinding(tb, TextBox.TextProperty, new Binding(feldname) { Source = quelle, Mode = BindingMode.OneWay });

        gr.Children.Add(bu);
        gr.Children.Add(tb);

        return gr;
    }

// Usage in Code 
Grid tbMit = glCtlTextbox.tbTextReadOnlyWithDeleteButton(1, 0, "Name", mit);
spStackpanel.Children.Add(tbMit);

//Now I need something like this, which is not working
tbMit.buDelete.Click += buDelete__Click;

Has anyone a hint, of how to approach this?

Thanks!

You have 2 solutions to define your user control:

  • XAML + code behind
  • code

In your first example, you can't found Delete cause you are casting your class to a Grid.

There is no Delete event in the Grid definition.

You should do this :

tbTextReadOnlyWithDeleteButton tbMit = new tbTextReadOnlyWithDeleteButton(1, 0, "Name", mit, "name", dat);

tbMit.Delete += your_event_handler;

I would suggest you to use the XAML + code behind approach. ( no one only use the code to define a control )

You can rigth click on any folder of your project in Visual Studio, and then select User Control.

You'll automatically have these files:

  • your_control.xaml
  • your_control.xaml.cs

C# + XAML :

c#:

public partial class your_control : UserControl
{
    public delegate void delete_event_handler(your_control sender);
    public event delete_event_handler delete;

    public your_control()
    {
        this.InitializeComponent();
    }

    private void on_bu_click(object sender, RoutedEventArgs e)
    {
        // the event is null if there is no listeners bind to it
        if (this.delete != null)
            this.delete(this);
    }
}

and XAML :

<UserControl x:Class="test_wpf.your_control"
         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>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="3*" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <!-- Use the FieldModifier property to define the visibility of the control outside the class-->
    <TextBlock x:Name="tb" x:FieldModifier="private" >Your text</TextBlock>
    <Button Grid.Column="1" x:Name="bu" x:FieldModifier="private" Click="on_bu_click">Delete</Button>
</Grid>

and then

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        your_control control = new your_control();
        control.delete += on_delete;
    }

    public void on_delete(your_control sender)
    {
        // your stuff
    }
}

The code only approach :

public class your_control : UserControl
{

    public TextBox tb { get; private set; }
    public Button bu { get; private set; }
    private Grid container;

    public your_control (/* your params*/)
    {
        this.tb = this.build_textbox();
        this.bu = this.build_button();
        this.container = new Grid();
        this.Content = this.container;
        this.container.Children.Add(this.tb);
        this.container.Children.Add(this.bu);
    }

    private TextBox build_textbox()
    {
        TextBox tb = new TextBox();
        return tb;
    }

    private Button build_button()
    {
        Button bu = new Button();
        return bu;
    }
}

and then :

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        your_control control = new your_control ();
        control.bu.Click += on_bu_click;
    }

    public void on_bu_click(object sender, EventArgs e)
    {
        // your stuff
    }
}

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