-1

There is a textbox in my mainwindow.xaml, when I enter the textbox, I expect the label in my usercontrol, known as View1.xaml will be update accordingly. However I realise the event is not raise at all in the user control when I type the textbox, can you tell me which part is wrong?

The event is able to raise in TextBox_TextChanged_1

my MainWindow.XAML

<Window xmlns:my="http://schemas.microsoft.com/winfx/2006/xaml/presentation/ribbon"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:testapplication"  x:Class="testapplication.MainWindow"
        Title="MainWindow" Height="964" Width="790">
    <Grid >
        <Button x:Name="OpenView1" Content="Open Window 1" HorizontalAlignment="Left" Margin="33,70,0,0" VerticalAlignment="Top" Width="111" RenderTransformOrigin="0.279,1.409" Click="OpenView1_Click"/>
        <Button x:Name="OpenView2" Content="Open Window 2" HorizontalAlignment="Left" Margin="33,169,0,0" VerticalAlignment="Top" Width="111" Click="OpenView2_Click"/>
        <Button x:Name="OpenView3" Content="Open Window 3" HorizontalAlignment="Left" Margin="33,259,0,0" VerticalAlignment="Top" Width="111" Click="OpenView3_Click"/>

        <local:View1 x:Name="ViewOne" HorizontalAlignment="Left" Margin="33,332,0,0" VerticalAlignment="Top" Height="226" Width="204"  Visibility="Hidden"/>
        <local:View2 x:Name="ViewTwo" HorizontalAlignment="Left" Margin="284,332,0,0" VerticalAlignment="Top" Height="226" Width="208" Visibility="Hidden"/>
        <local:View3 x:Name="ViewThree" HorizontalAlignment="Left" Margin="534,332,0,0" VerticalAlignment="Top" Height="226" Width="196" Visibility="Hidden"/>
        <TextBox HorizontalAlignment="Left" Height="42" Margin="326,70,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="182" FontSize="22" TextChanged="TextBox_TextChanged_1"/>

    </Grid>
</Window>

my MainWindow.cs

namespace testapplication
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
           //InitializeComponent();
        }

        //event handler
        public event EventHandler<EventArgs> changedText;

        private void OpenView1_Click(object sender, RoutedEventArgs e)
        {
            ViewOne.Visibility = Visibility.Visible;
        }

        private void OpenView2_Click(object sender, RoutedEventArgs e)
        {
            ViewTwo.Visibility = Visibility.Visible;
        }

        private void OpenView3_Click(object sender, RoutedEventArgs e)
        {
            ViewThree.Visibility = Visibility.Visible;
        }

        private void TextBox_TextChanged_1(object sender, TextChangedEventArgs e)
        {

            if (changedText != null)
            {
               changedText(this, e);
            }
        }


    }
}

This is my UserControl, known as View1.xaml, it is included in my MainWindow.Xaml

namespace testapplication
{
    /// <summary>
    /// Interaction logic for View1.xaml
    /// </summary>
    public partial class View1 : UserControl
    {

        private MainWindow newWindow = new MainWindow();
        public View1()
        {
            InitializeComponent();

            newWindow.changedText += newWindow_ChangeText;
        }

        void newWindow_ChangeText(object sender, EventArgs e)
        {
            ViewOnelabel.Content = "Happy";
        }




    }
}

The problem is my ViewOnelabel.Content = "Happy" did not execute at all, it remain unchanged

user2399158
  • 561
  • 3
  • 10
  • 26
  • Use MVVM. This can easily be done using Bindings. – Fildor Mar 28 '18 at 09:18
  • How do I do it? can you show me an example? – user2399158 Mar 28 '18 at 09:21
  • 1
    Just go to youtube and search for WPF and MVVM. There will be tons of beginner's tutorials. I really recommend you do that. It will make your life way easier. – Fildor Mar 28 '18 at 09:22
  • 1
    There's no actual need for a view model. The UserControl should simply expose a dependency property, which could be bound to the TextBox's Text property. In the UserControl's XAML you would bind the Content of ViewOnelabel to the UserControl dependency property by a RelativeSource Binding. – Clemens Mar 28 '18 at 09:31
  • @Clemens While I agree with you about this case, I think it would still be a good idea for the OP to learn about how to use and implement MVVM. – Fildor Mar 28 '18 at 09:49
  • 1
    @Fildor Sure, the important point is the bindable dependency property, which could then be bound to a view model as well as to another element's property. – Clemens Mar 28 '18 at 09:51

4 Answers4

0

There are a few things I would like to point out.

The equivalent of a winforms label in wpf is a TextBlock. A wpf label is actually a type of contentcontrol. Hence the content property.

In wpf there are routed events. These "bubble" up ( and tunnel down ) the visual tree. That means you can handle an event in the window from a control in a usercontrol inside it.

But mainly. I encourage you to look into the MVVM pattern. I've put together some code which illustrates these points. I'd recommend just using binding and mvvm though.

My MainWindow markup:

<Window
    Title="MainWindow" Height="350" Width="525"
    
    TextBoxBase.TextChanged="Window_TextChanged"
    
    <Window.DataContext>
    <local:MainWindowViewModel/>
    </Window.DataContext>
    <Grid>
        <StackPanel>
            <Label Name="OutputLabel"/>
            <TextBlock Text="{Binding OutputString}"/>
            <local:UserControl1/>
        </StackPanel>
    
    </Grid>
</Window>

Notice that it handles a textchanged event and because that's routing it will get the event from UserControl1 inside it. Code behind:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Window_TextChanged(object sender, TextChangedEventArgs e)
    {
        OutputLabel.Content = $"Happy {((TextBox)e.OriginalSource).Text}";
    }
}

You don't do anything with the text from your textbox in your handler but I have some code there proves you could get at that from mainwindow if you wanted.

My viewmodel:

public class MainWindowViewModel : INotifyPropertyChanged
{
    private string inputString;

    public string InputString
    {
        get { return inputString; }
        set
        {
            inputString = value;
            OutputString = $"{inputString.Length} characters entered";
            RaisePropertyChanged();
        }
    }

    private string outputString;

    public string OutputString
    {
        get { return outputString; }
        set
        {
            outputString = value;
            RaisePropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Usercontrol1 just has a textbox:

<Grid>
    <TextBox Text="{Binding InputString, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>

As you type in that textbox, the text is transferred to the bound property in my viewmodel. That hits the code in my setter. This in turn sets OutputString which is bound to my textblock.

Text changes in both my label and textblock as I type.

Here's a link to my sample on onedrive https://1drv.ms/u/s!AmPvL3r385QhgpgOPNKPs-veFJ2O3g

Sigmarod
  • 85
  • 12
Andy
  • 11,864
  • 2
  • 17
  • 20
-1

The main problem here is that your View1 class is subscribing to an event on a new MainWindow instance, not the MainWindow instance created by your application on start. Since your MainWindow class has a reference to your View1 class (a named member "ViewOne") you should just change it from the MainWindow class.

private void TextBox_TextChanged_1(object sender, TextChangedEventArgs e)
        {

            ViewOne.ViewOneLabel.Content = "Happy";
        }

Get rid of the chenagedText event handler and all the code in the View1.xaml.cs... you don't need it.

Note: I am hoping that you are just playing around and learning here... there is no way I would condone building a WPF application in this way.

MrShoes
  • 485
  • 10
  • 28
  • I am still learning, I was hoping to build a application using the eventhandler way, is there anything I can do on the view1 to make it work? – user2399158 Mar 28 '18 at 09:16
  • @user2399158 https://stackoverflow.com/a/19654812/1859959 it's a fairly complex, but good way to use MVVM with WPF and navigation, which You seems to pursue. – ntohl Mar 28 '18 at 09:30
-1

You could only use the event of the MainPage. I recomment you to add a Property to the UserControl. In my case I call it Text.

public string Text
{
    set { ViewOneLabel.Content = value; }
}

In the MainWindow use the Property within the TextChanged Event.

private void TextBox_TextChanged_1(object sender, TextChangedEventArgs e)
{
    OpenView1.Text = TextBox.Text;
}
M Stoerzel
  • 300
  • 1
  • 13
-1

You are creating a new instance of MainWindow in your UserControl. What you want to do is to hook up an event handler to the instance that you actually see on the screen. You can get a reference to this one using the Window.GetWindow method:

public partial class View1 : UserControl
{
    public View1()
    {
        InitializeComponent();

        Loaded += (s, e) => 
        {
            Window mainWindow = Window.GetWindow(this) as MainWindow;
            if(mainWindow != null)
                mainWindow.changedText += newWindow_ChangeText;
        };
    }

    void newWindow_ChangeText(object sender, EventArgs e)
    {
        ViewOnelabel.Content = "Happy";
    }
}
mm8
  • 163,881
  • 10
  • 57
  • 88