Search code examples
wpfbindinguser-controlsdatacontext

WPF Bind Textbox in main windows from user controls


I'm new in WPF and a trying to bind a textbox located in mainwindow, from an user control.

<Window x:Class="Databinding.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="360" Width="490">
<Grid HorizontalAlignment="Left" Width="480">
    <TextBox x:Name="EventTitle" HorizontalAlignment="Left" Height="23" Margin="40,19,0,0" TextWrapping="Wrap" Text="{Binding Path=FirstName}"   VerticalAlignment="Top" Width="120"/>
    <Button Content="Button" HorizontalAlignment="Left" Margin="195,20,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
    <StackPanel x:Name="Stck_Main" HorizontalAlignment="Left" Height="230" Margin="22,75,0,0" VerticalAlignment="Top" Width="439"/>
    <Button Content="UC" HorizontalAlignment="Left" Margin="371,20,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_1"/>

</Grid>

I also created a class to manage value update

class UIcontrol : INotifyPropertyChanged

{
    public event PropertyChangedEventHandler PropertyChanged;

    private string _firstName;

    protected void Notify(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public string FirstName
    {
        get { return _firstName; }
        set
        {
            if (value != _firstName)
            {
                _firstName = value;
                Notify("FirstName");
            }
        }
    }


}

My question: Inside the main window i used an simple user control. I want to bind the textbox value from this user control. the binding operate from a button in mainwindow, but nothing happens from user control. I suppose that the datacontextis wrong somewher, but could youd please help me to find the right way.

code behind the mainwindow

 public partial class MainWindow : Window
{
    private UIcontrol viewModel;

    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        viewModel = new UIcontrol();
        DataContext = viewModel;
        viewModel.FirstName = "Mike";
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        UC1 myUC = new UC1();
        Stck_Main.Children.Clear();
        Stck_Main.Children.Add(myUC);
    }

}

The user control code behind is

public partial class UC1 : UserControl
{

    private UIcontrol viewModel;

    public UC1()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        viewModel = new UIcontrol();
        DataContext = viewModel;
        viewModel.FirstName = "Doe";
    }


}

And it's XAML:

UserControl x:Class="Databinding.UC1"
         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 Margin="0,0,10,43">
    <Canvas Height="194" Margin="25,30,71,0" VerticalAlignment="Top" Background="White">
        <Button Content="Button" Canvas.Left="100" Canvas.Top="81" Width="75" Click="Button_Click" />
    </Canvas>
</Grid>

Solution

  • There could be many other solutions, but as I said in my comments following solution will work and will give you an idea of problem.

    Only updates in UC1 code behind

    public partial class UC1 : UserControl
    {
        public UC1()
        {
            InitializeComponent();
        }
    
        private UIcontrol viewModel;
    
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var window = FindParent<Window>(this);
    
            if(window != null)
            {
                var vm = window.DataContext as UIcontrol;
                if(vm != null)
                {
                    vm.FirstName = "Doe";
                }
                else
                {
                    viewModel = new UIcontrol();
                    window.DataContext = viewModel;
                    viewModel.FirstName = "Doe";
                }
            }
        }
    
        public static T FindParent<T>(DependencyObject child) where T : DependencyObject
        {
            //get parent item
            DependencyObject parentObject = VisualTreeHelper.GetParent(child);
    
            //we've reached the end of the tree
            if (parentObject == null) return null;
    
            //check if the parent matches the type we're looking for
            T parent = parentObject as T;
            if (parent != null)
                return parent;
            else
                return FindParent<T>(parentObject);
        }
    }
    

    As a side note please use proper notation for ViewModel names UIcontrol for ViewModel is bit confusing.. :)