User Tools

Site Tools


notes:uwp:binding

Binding in UWP

Below there are a few examples of rarely used binding techniques.

Relative binding: Bind the target element to itself. In this example, a TextBlock shows a value of its FontSize property:

  • RelativeSource may be useful when the binding is specified in a ControlTemplate.
<!-- displays 23 -->
<TextBlock Text="{Binding RelativeSource={RelativeSource Self}, Path=FontSize}" FontSize="23" />

Binding to an element of a collection: In a DataTemplate, bind an element of a GradientStops collection to the Color property of an Ellipse's brush:

<Button HorizontalAlignment="Center">
    <LinearGradientBrush>
        <GradientStop Offset="0" Color="Red" />
        <GradientStop Offset="1" Color="Blue" />
    </LinearGradientBrush>
 
    <Button.ContentTemplate>
        <DataTemplate>
            <Ellipse Width="200" Height="150" Fill="{Binding}" StrokeThickness="8">
                <Ellipse.Stroke>
                    <SolidColorBrush Color="{Binding GradientStops[1].Color}" />
                </Ellipse.Stroke>
            </Ellipse>
        </DataTemplate>
    </Button.ContentTemplate>
</Button>

UpdateSourceTrigger: Apply changes to the binding source immediately rather than when the user leaves a text box:

  • When UpdateSourceTrigger is set to PropertyChanged the binding source is updated whenever the binding target value changes.
<TextBox Text="{Binding Path=FirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

UpdateSourceTrigger: As the user types in TextBox1, send the characters from TextBox1 to TextBox2 and vice-versa when the user types in TextBox2, send the characters from TextBox2 to TextBox1:

<StackPanel>
  <!-- TextBox1 is the binding target -->
  <!-- TextBox2 is the binding source -->
  <TextBox x:Name="TextBox1" 
           Text="{Binding Path=Text, ElementName=TextBox2, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
  <TextBox x:Name="TextBox2" />
</StackPanel>  

UpdateSourceTrigger: You can change the behavior of TwoWay bindings so that values are not copied to the source automatically, but only at times of your choosing. To do this, set the Binding.UpdateSourceTrigger property to Explicit. You can then call GetBindingExpression on the target to get a BindingExpression object, and then call BindingExpression.UpdateSource to programmatically update the data source.

  • When UpdateSourceTrigger is set to Explicit the binding source is updated only when the BindingExpression.UpdateSource method is called.

In this example, the source (an Employee object) is updated only when the user clicks the Update button:

<TextBox x:Name="EmployeeNameTextBox" 
         Text="{Binding Path=EmployeeName, Mode=TwoWay, UpdateSourceTrigger=Explicit}" />
<Button Content="Update" Click="UpdateButton_Click" />
public sealed partial class MainPage : Page
{
    Employee empl;
 
    public MainPage()
    {
        this.InitializeComponent();
 
        empl = new Employee { EmployeeName = "AAA" };
        Panel.DataContext = empl;
    }
 
    private void UpdateButton_Click(object sender, RoutedEventArgs e)
    {
        // Assume the user entered a string "BBB" to EmployeeNameTextBox. 
        // empl.EmployeeName is still "AAA"
 
        BindingExpression expr = EmployeeNameTextBox.GetBindingExpression(TextBox.TextProperty);
        expr.UpdateSource();
 
        // empl.EmployeeName is now "BBB"
    }
 
    class Employee
    {
        public string EmployeeName { get; set; }
    }
}

Binding to an element of a dictionary

<StackPanel x:Name="Panel">
    <!-- displays BBB -->
    <TextBlock Text="{Binding Path=[e2].EmployeeName}" />
</StackPanel>  
using System.Collections.Generic;
...
public sealed partial class MainPage : Page
{
    public Dictionary<string, Employee> Employees = new Dictionary<string, Employee>();
 
    public MainPage()
    {
        this.InitializeComponent();
 
        Employees.Add("e1", new Employee { EmployeeName = "AAA" });
        Employees.Add("e2", new Employee { EmployeeName = "BBB" });
 
        Panel.DataContext = Employees;
    }
 
    public class Employee
    {
        public string EmployeeName { get; set; }
    }
}

Programmatic binding Bind the TextWrapping property of MyTextBox to the TextWrapping property of MyBindingSource:

Binding binding = new Binding
{
    Source = MyBindingSource,
    Path = new PropertyPath("TextWrapping"),
    Mode = BindingMode.TwoWay
};
MyTextBox.SetBinding(TextBox.TextWrappingProperty, binding);

FallbackValue and TargetNullValue:

  • FallbackValue gets or sets the value to use when the binding is unable to return a value. This is useful to handle conversion and formatting errors.
  • TargetNullValue gets or sets the value that is used in the target when the value of the source is null.
<TextBlock Text="{x:Bind EmployeeName, FallbackValue='John Smith', TargetNullValue='New Employee'}" />

Binding to an attached property (does not work in UWP): Wrap the property name in parentheses. For example, the path (Grid.Row) retrieves the row number where the element is placed in a Grid:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
 
    <TextBlock Grid.Row="0" Text="{Binding Path=(Grid.Row)}" />
    <TextBlock Grid.Row="1" Text="{Binding Path=(Grid.Row)}" />
    <TextBlock Grid.Row="2" Text="{Binding Path=(Grid.Row)}" />
</Grid>

x:Bind with casting to a Person model:

<ListView x:Name="ListView1" ... />
...
<TextBox Text="{x:Bind ((model:Person)ListView1.SelectedItem).FirstName}" />

Update x:Bind whenever the source data object changes:

<TextBlock Text="{x:Bind Person.FirstName, Mode=OneWay}" />
private Person person;
public Person Person
{
    get { return person; }
    set
    {
        person = value;
        this.Bindings.Update();
    }
}

Links

notes/uwp/binding.txt · Last modified: 2017/07/21 by leszek