Amjad Abdelrahman
Amjad Abdelrahman

Reputation: 3542

WPF DataBinding when using usercontrols

i'm new to WPF and the MVVM pattern, i'm trying to make an app that uses several controls so i create each control separately and i am facing some difficulty for how to share data between controls

lets say i have a control that has a label and another control that contains a textbox, in the main window i want when i add the two custom controls i need the label control to show what i'm typing in the text box, i know how to implement that if i use the label and textbox directly in my window but i need that to solve similar issue, here is the Label Control

<UserControl x:Class="TestWPF2.Views.LabelControl"
             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>
        <Label ></Label>
    </Grid>
</UserControl>

TextBox Custom control

<UserControl x:Class="TestWPF2.Views.TextBoxControl"
             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>
        <TextBox ></TextBox>
    </Grid>
</UserControl>

and this is the window code

<Window x:Class="TestWPF2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:V="clr-namespace:TestWPF2.Views"
        xmlns:Controls="clr-namespace:TestWPF2.Views"
        Title="MainWindow" Height="350" Width="525">
    <DockPanel LastChildFill="True">

        <Controls:TextBoxControl   ></Controls:TextBoxControl>
        <Controls:LabelControl   ></Controls:LabelControl>
    </DockPanel>
</Window>

Upvotes: 1

Views: 913

Answers (3)

blindmeis
blindmeis

Reputation: 22435

you can use dependency properties to fit your usercontrols.

<UserControl x:Class="TestWPF2.Views.TextBoxControl"
         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"
         x:Name="uc">
<Grid>
    <TextBox Text="{Binding ElementName=uc, Path=MyText}"></TextBox>
</Grid>
</UserControl>

codebehind add the dependency property

   public static readonly DependencyProperty MyTextProperty =
     DependencyProperty.Register("MyText", typeof(string),
     typeof(TextBoxControl), new FrameworkPropertyMetadata(""));

    public stringMyText
    {
        get { return (bool)GetValue(MyTextProperty); }
        set { SetValue(MyTextProperty, value); }
    }

now you can use this control in any view like this:

 <Window x:Class="TestWPF2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:V="clr-namespace:TestWPF2.Views"
    xmlns:Controls="clr-namespace:TestWPF2.Views"
    Title="MainWindow" Height="350" Width="525">
   <DockPanel LastChildFill="True">

    <Controls:TextBoxControl MyText="{Binding Path=YourPropertyYouWannaBindTo}"  />
    <Controls:LabelControl   ></Controls:LabelControl>
</DockPanel>
 </Window>

Upvotes: 0

JJJCoder
JJJCoder

Reputation: 16916

Just knocked up an example that might be of use. Remember to use the output window to identify binding errors if needed.

In this example, my window is bound to a viewmodel, which has a property called 'Model'. The model has a Forename and surname property.

We have a label in the main window and a textbox in a control. Between this answer and my first, I'll let you finish it off to get it how you want.

Main Window Code (in this case the datacontext has been quickly set in code behind, though there are many ways to do it).

Code Behind

  public partial class BindingTest : Window
  {
    public BindingTest()
    {
      InitializeComponent();

      Models.NamesModel nm = new Models.NamesModel();
      nm.Forename = "Bill";
      nm.Surname = "Gates";
      ViewModels.NamesViewModel vm = new ViewModels.NamesViewModel(nm);


      this.DataContext = vm;
    }
  }

Window

<Window x:Class="WPFTutSimple.BindingTest"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ctrl="clr-namespace:WPFTutSimple.UserControls"
        Title="BindingTest" Height="300" Width="300"
        >
  <StackPanel>

    <Label Content="Name"></Label>
    <Label Content="{Binding Path=Model.Surname}"></Label>
    <ctrl:TextBoxControl />

  </StackPanel>
</Window>

User Control Code.

<UserControl x:Class="WPFTutSimple.UserControls.TextBoxControl"
             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">
  <StackPanel>
    <TextBox Text="{Binding Path=Model.Surname, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
             Width="200" BorderBrush="Black" HorizontalAlignment="Left"></TextBox>

  </StackPanel>
</UserControl>

If you want/need to see what is going on in your usercontrols (and you are using WPF proper, not WinRT) you can tap into the DataContextChanged Event in the user control and check the 'e' values as the datacontext changes:

  public partial class TextBoxControl : UserControl
  {
    public TextBoxControl()
    {
      InitializeComponent();
      this.DataContextChanged += TextBoxControl_DataContextChanged;
    }

    void TextBoxControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
      //Set breakpoint here...
    }
  }

Upvotes: 0

JJJCoder
JJJCoder

Reputation: 16916

With binding, controls will inherit the datacontext of their parent.

If you set the window datacontext to "Model" (or the controls datacontext to "Model" if you need to keep it restrained) and that model has a property called "SomeText", you could bind the textbox and label as shown below:

<TextBox BorderBrush="Black" Text="{Binding Path=Model.SomeText,UpdateSourceTrigger=PropertyChanged}" />

If you need further info, please let me know. Bindings are a beast to start with.

You shouldn't need any code behind to wire up the controls.

Upvotes: 2

Related Questions