Search code examples
c#wpfbindinguser-controls

Relations between UserControl and MainWindow


How could I make possible to access data/properties from a UserControl and the parent, MainWindow (and viceversa)? For example, say I have a TextBox in my MainWindow called mainTextBox. Then I create a UserControl with another TextBox called ucTextBox. I also have a button called ucButton in the UserControl that should popup a MessageBox with the product of the values mainTextBox.Text * ucTextBox.Text (converted to double, to make it work).

What I really want to know is how to achieve to do this dynamically, with a button that allows to create more UserControls that are capable to interact with the parent. In this case it makes no sense to name every UserControl.

I've tried several things, mainly with get,set properties but with no desired outcome. I'm not sure if I need to use UserControl, but it seems to, I've read that CustomControl is for a deep customization but I don't need that.


Solution

  • Here is just a quick sample to get you started (and what probably was meant by mr. @Adriano):

    RootViewModel.cs:

    public class RootViewModel :INotifyPropertyChanged
    {
        #region Implementation of INotifyPropertyChanged
    
        public event PropertyChangedEventHandler PropertyChanged = delegate {};
    
        private void OnPropertyChanged(string propertyName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    
        #endregion
    
        private double _x;
        private double _y;
    
        public double X
        {
            get { return _x; }
            set
            {
                _x = value;
                OnPropertyChanged("X");
            }
        }
    
        public double Y
        {
            get { return _y; }
            set
            {
                _y = value;
                OnPropertyChanged("Y");
            }
        }
    
        public double XY
        {
            get { return _x * _y; }
        }
    }
    

    UserControl1.xaml:

    <UserControl x:Class="WpfApplication2.UserControl1"
             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:DesignWidth="200">
    <Grid>
        <GroupBox Header="User Control">
            <StackPanel>
                <Label Content="Y:" />
                <TextBox Text="{Binding Path=Y, UpdateSourceTrigger=PropertyChanged, FallbackValue=1}" Margin="5" />
                <Button Content="Press me" Click="OnButtonClick" />
            </StackPanel>
        </GroupBox>
    </Grid>
    

    UserControl1.xaml.cs:

    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }
    
        private void OnButtonClick(object sender, RoutedEventArgs e)
        {
            var viewModel = (RootViewModel)DataContext;
            var resultMessage = string.Format("{0} * {1} = {2}", viewModel.X, viewModel.Y, viewModel.XY);
    
            MessageBox.Show(resultMessage, "X * Y");
        }
    }
    

    MainWindow.xaml:

    <Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:WpfApplication21="clr-namespace:WpfApplication2"
        Title="Main Window" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <StackPanel>
            <Label Content="X:" />
            <TextBox Text="{Binding Path=X, UpdateSourceTrigger=PropertyChanged, FallbackValue=1}" Margin="5" Height="24" />
        </StackPanel>
        <WpfApplication21:UserControl1 Grid.Row="1" Margin="5" />
    </Grid>
    

    MainWindow.xaml.cs:

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
    
            DataContext = new RootViewModel
            {
                X = 5,
                Y = 7
            };
        }
    }