3

I'm using .net 4.5, in a WPF project. I would like to raise a TextBox TextChangedEvent. This is what I have done so:

tb.RaiseEvent(new RoutedEventArgs(TextBox.TextChangedEvent));

I've done the same sort of RaiseEvent on a Button.ClickEvent before, how can I do this one?

this produces an error as follows:

Exception:Thrown: "Object of type 'System.Windows.RoutedEventArgs' cannot be converted to type 'System.Windows.Controls.TextChangedEventArgs'." (System.ArgumentException) A System.ArgumentException was thrown: "Object of type 'System.Windows.RoutedEventArgs' cannot be converted to type 'System.Windows.Controls.TextChangedEventArgs'."

[EDIT]

The actual textbox text changed is handled by an attached behavior as follows. The place where I want to programmatically raise the event is in another control's attached behavior. In the later behavior I do have the textbox object.

public class textboxTextChangedBehavior : Behavior<TextBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.TextChanged += OnTextChanged;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.TextChanged -= OnTextChanged;
        base.OnDetaching();
    }

    private void OnTextChanged(object sender, TextChangedEventArgs args)
    {
        var textBox = (sender as TextBox);
        if (textBox != null)
        {
            //Populate ObservableCollection
        }
    }
}

Place where I try to raise the event:

public class FindPopupBehavior : Behavior<Popup>
{
    protected override void OnAttached()
    {
        AssociatedObject.Opened += _OpenFindPopup;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.Opened -= _OpenFindPopup;
    }

    void _OpenFindPopup(object sender, EventArgs e)
    {
        //Fake a TextBox text changed event
        if (TextBoxObject == null)
            return;

        TextBox tb = TextBoxObject as TextBox;

        if (tb.Text == "")
            return;

        tb.RaiseEvent(new RoutedEventArgs(TextBox.TextChangedEvent));
    }

    public static readonly DependencyProperty TextBoxProperty =
        DependencyProperty.Register("TextBoxObject", typeof(TextBox), typeof(FindPopupBehavior), new UIPropertyMetadata(null));

    public object TextBoxObject
    {
        get { return (object)GetValue(TextBoxProperty); }
        set { SetValue(TextBoxProperty, value); }
    }
}

[EDIT2]

The textbox resides in a popup upon this popup closing an ObservableCollection is cleared, the textbox text remains, although hidden. If the popup is reopened and the textbox has text it needs to repopulate the ObservableCollection. It does this population in the textchanged behavior. This is why I was thinking to fake an event.

Hank
  • 2,456
  • 3
  • 35
  • 83

5 Answers5

2

Manually raising .NET events is unadvisable, even if for no other reason than it is unrequired. Think about it... you don't really want to raise an event. You're not seeking the functionality of the event, so why raise it?

If I understand your situation correctly, then surely, what you actually want to do is to execute a particular section of your code. As such, your problem is caused because that section of code is currently encapsulated within an event handler. However, that doesn't mean that you have to raise that event to execute that code.

Instead, just simply move the relevant code into a method, which you can call from the event handler and from wherever else you want and all without unnecessarily raising any events:

private void OnTextChanged(object sender, TextChangedEventArgs args)
{
    var textBox = (sender as TextBox);
    if (textBox != null)
    {
        PopulateObservableCollection();
    }
}

private void PopulateObservableCollection()
{
    // Populate ObservableCollection
}

If you particularly need to access the TextBox, then please describe your situation further... there is always a way.


UPDATE >>>

Think about this logically... you want to call this method and you need access to the TextBox in the Popup and you need to do it each time the Popup is opened. So why not just handle the Popup.Opened Event?:

private void PopupOpened(object sender, EventArgs e)
{
    // Check TextBox and Populate ObservableCollection
}
Sheridan
  • 68,826
  • 24
  • 143
  • 183
  • 1
    The first paragraph is definitely key. Still trying to figure how to call the new method from the popup behavior? – Hank Jun 24 '14 at 09:12
  • I have already thought about this, I was trying to avoid code duplication. Which means that separating out the code in the first place is pointless. Hmm I think I have it, I have produced a separate static class, actually I already had a singleton class that holds my ObservableCollection so transferred the method into this, now is accessible from both behaviors. – Hank Jun 24 '14 at 12:46
1

You can raise event manully like

    MouseButtonEventArgs args = new MouseButtonEventArgs(Mouse.PrimaryDevice,100, MouseButton.Left);
    args.RoutedEvent = UIElement.PreviewMouseLeftButtonUpEvent;
    tb.RaiseEvent(args);
Dhaval Patel
  • 7,471
  • 6
  • 37
  • 70
0

One way is that you can do like this..

   EventName.Raise(this, new EventArgs());
Alam248
  • 1
  • 1
  • I am doing this from an attached behavior: TextChangedEvent.Raise(tb, new EventArgs()); didn't work or have I gone astray. – Hank Jun 24 '14 at 06:42
  • Added some more information as an edit in the question – Hank Jun 24 '14 at 06:59
0

Why don't you call the method of the event directly? I have created a small sample application for you:

It does the following:

  • I have a button and a textbox. On the textbox is a OnTextChanged event, and I want when I click on the button, to execute that textbox event.

First, your WPF application, that in my case, contains just a grid with in it a textbox and a button.

<Grid>
    <TextBox Name="txtTextBox"></TextBox>
    <Button Name="btnDemo" Content="Click me"></Button>
</Grid>

I know that layout wise, this is rubbish, but it's just for demonstrating.

In your code behind, you need to do a few things:

Add an event handler for the button and for the textbox:

public MainWindow()
{
    InitializeComponent();

    btnDemo.Click += BtnDemoOnClick;
    txtTextBox.TextChanged += TxtTextBoxOnTextChanged;
}

Here's the code for your TxtTextBoxOnTextChanged event:

private void TxtTextBoxOnTextChanged(object sender, TextChangedEventArgs textChangedEventArgs)
{
    MessageBox.Show("The textbox event has been fired.");
}

As you see, this just shows an message box.

And then the event of your button:

private void BtnDemoOnClick(object sender, RoutedEventArgs routedEventArgs)
{
    TxtTextBoxOnTextChanged(this, new TextChangedEventArgs(routedEventArgs.RoutedEvent, UndoAction.None));
}

I hope it helped.

Complexity
  • 5,682
  • 6
  • 41
  • 84
  • Not sure if this does, my actual text changed event is handled by an attched behavior and this RaiseEvent is occuring in another control's attached behavior. I will place extra information in the question – Hank Jun 24 '14 at 06:51
0

this could end in an stackoverflow because if recall the Event for your object it will again be catched by your textboxTextChangedBehavior

so instead of creating a loop you can simple change your

private void OnTextChanged(object sender, TextChangedEventArgs args)
    {
        var textBox = (sender as TextBox);
        if (textBox != null)
        {}
    }

to

private void OnTextChanged(object sender, TextChangedEventArgs args)
    {
        var textBox = (sender as TextBox);
        if (textBox != null)
        {}

        // now your textboxTextChangedBehavior does't block your event 
        args.Handled = false;
    }

[EDIT]

mhh maybe the problem is more how you try to achieve your goal.

but if i understand you correctly your popup Opened and you try to raise the TextChanged, right?

so you could set the Text in your _OpenFindPopup (add an # or what ever) which will raise your TextChanged and now you can remove the # and populate your ObservableCollection

WiiMaxx
  • 5,322
  • 8
  • 51
  • 89
  • The actual text will not be changing, the textbox is in a Popup, there is an ObservableCollection that gets cleared when the popup closes, when the popup opens and has text in the textbox it needs to populate the ObservableCollection again. The place where it gets populated is when the textbox text changes so I figure I will just fake an event. – Hank Jun 24 '14 at 07:45