Data Binding in Wpf User Controls

Data Binding in WPF User Controls

if you look at your output window you should see the binding exception.

The problem you have is the following: within your usercontrol you will bind the label to the DP ProtocolNumber of your usercontrol and not the DataContext, so you have to add for example the element name to the binding.

<UserControl Name="MainOptionsPanel"
x:Class="ExperienceMainControls.MainControls"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="uc"
>
<Label Height="Auto" Name="numberLabel">Protocol:</Label>
<Label Content="{Binding Path=ProtocolNumber, ElementName=uc}" Name="protocolNumberLabel"/>
(...)
</UserControl>

EDIT: to clear some things up, your usercontrol also works if you change the binding in your MainWindow. but you have to bind to the DataContext of the MainWindow with RelativeSource.

    <expControl:MainControls ProtocolNumber="{Binding Path=Number, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />

Data binding to a UserControl in WPF

You set the DataContext in the Control to itself, thus overwriting the DataContext when using this Control in other controls. Taking your binding as example in your situation:

<src:BlueTextBox BlueText="{Binding Path=MyString}" /> 

Once loaded and all the Datacontext is set, it will look for the path MyString in your BlueTextBox thing control due to you setting the DataContext to it. I guess this is not how you intended this to work ;).

Solution:

Change the text binding either one of the 2 bindings:

{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type src:BlueTextBox}}, Path=BlueText}

or

Name your control Root (or something like that)

<UserControl x:Name="Root"

{Binding ElementName=Root, Path=BlueText}

And remove the

DataContext = this;

from the constructor of your UserControl and it should work like a charm..

How to set DataBinding for UserControl with ViewModel

A UserControl that is supposed to operate on a particular view model class - or more precisely on a class with a particular set of public properties - may directly bind to the view model properties in its XAML.

Given a view model like

public class Model
{
public string Something { get; set; }
}

you may write a UserControl with nothing more than this XAML

<UserControl ...>
...
<TextBox Text="{Binding Something}" />
...
</UserControl>

and this code behind

public partial class Wizard : UserControl
{
public Wizard()
{
InitializeComponent();
}
}

If you now set its DataContext to an instance of Model (or any other class with a Something property), it will just work:

<local:Wizard DataContext="{Binding MyModel}"/>

Since the value of the DataContext property is inherited from parent to child elements, this will also work:

<StackPanel DataContext="{Binding MyModel}">
<local:Wizard/>
</StackPanel>

However, the UserControl still dependends on the existence of a Something property in its DataContext. In order to get rid of this dependence, your control may expose a dependency property

public static readonly DependencyProperty MyTextProperty =
DependencyProperty.Register(nameof(MyText), typeof(string), typeof(Wizard));

public string MyText
{
get { return (string)GetValue(MyTextProperty); }
set { SetValue(MyTextProperty, value); }
}

and bind the element in its XAML to its own property

<UserControl ...>
...
<TextBox Text="{Binding MyText,
RelativeSource={RelativeSource AncestorType=UserControl}}"/>
...
</UserControl>

Now you would bind the control's property instead of setting its DataContext:

<local:Wizard MyText="{Binding MyModel.Something, Mode=TwoWay}"/>

WPF User Control Binding

This markup requires you to add a dependency property called File to the ControlUploadDataItem control:

<controls:ControlUploadDataItem File="{Binding}" />

You should also avoid setting the DataContext property in the constructor of the control as this will prevent it from inherting the DataContext from the parent element in the object tree:

this.DataContext = new UploadDataViewModel();

You don't really need an UploadDataViewModel here. The File property belongs to the control and is bound to the FileInfo in the source collection of the ListView in the ItemTemplate of the same. The ControlUploadDataItem control can then bind properties of its own File dependency property.

WPF Cross User Control Data Binding

EmployeeRecordControl seems redundant. Instead of that, just use a DataGrid directly, and bind its ItemsSource and SelectedItem to two properties of a view model class like this:

public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

public ObservableCollection<Employee> Employees { get; }
= new ObservableCollection<Employee>();

private Employee selectedEmployee;

public Employee SelectedEmployee
{
get => selectedEmployee;
set
{
selectedEmployee = value;
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(SelectedEmployee)));
}
}
}

Then create and bind to the view model like this:

<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>

<DataGrid ItemsSource="{Binding Employees}"
SelectedItem="{Binding SelectedEmployee}"
CanUserAddRows="False"/>

<local:EmployeeDetailControl Grid.Column="1"
DataContext="{Binding SelectedEmployee}"/>
</Grid>

wpf, binding data to child of another usercontrol

In your User control, you should add a get accessor like this:

public int ListCount {
get {
return this.lbDemo.Items.Count;
}
}

And in your Main Window, you call it like this:

<TextBlock Text="{Binding ElementName=userControlDemo, Path=ListCount, StringFormat='there are  {0} items in the listbox of Usercontrol1'}" />

Custom user control in WPF with data binding

When you do

<UserControl ... DataContext="{Binding RelativeSource={RelativeSource Self}}">

you effectively overwrite DataContext that would normally be passed to your control from visual tree and you change binding context for bindings within NameControl control. I would suggest to remove that and do that per binding

<TextBlock ... Text="{Binding FirstName, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
<TextBlock ... Text="{Binding LastName, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />

or to make it simpler give UserControl some name and use it for bindings within your control

<UserControl... x:Name="myUserControl">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Width="100" Text="{Binding FirstName, ElementName=myUserControl}" />
<TextBlock Grid.Column="1" Width="100" Text="{Binding LastName, ElementName=myUserControl}" />
</Grid>
</UserControl>

DataBinding to a UserControl inside of a UserControl

This can all be greatly simplified.

First, get rid of every Canvas in your UserControls. Canvas isn't just a neutral panel/container control. The Canvases will cause everything to be superimposed. Only use a Canvas when you want to position children arbitrarily, and potentially superimposed. WPF layout usually uses "flow" and relative positioning. The standard layout parents are StackPanel, Grid, WrapPanel, and the occasional UniformGrid. You can omit the ItemsPanelTemplate for the ItemsControl, since the default is already a vertically-oriented StackPanel.

How to databind property from view model to custom user control in WPF?

I managed to solve it by setting my control DataContext to grid like MyGrid.DataContext = new BindingControlViewModel(); instead of setting it on the control itself like this.DataContext = new BindingControlViewModel();.



Related Topics



Leave a reply



Submit