Search code examples
c#wpfxamldata-bindinguser-controls

How do I get data binding to work both ways, when I'm programmatically changing the user control?


I have a WPF application, which uses User Settings, and binds it to a <TextBox> like this:

<Window x:Class="SampleApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    <Grid>
        <TextBox x:Name="textbox" Text="{Binding Source={StaticResource Settings}, Path=Default.Folder}"/>
    </Grid>
</Window>

The App.xaml looks like this:

<Application x:Class="SampleApp.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:properties="clr-namespace:SampleApp.Properties"
             ShutdownMode="OnExplicitShutdown"
             Startup="Application_Startup">
    <Application.Resources>
        <properties:Settings x:Key="Settings"/>
    </Application.Resources>
</Application>

And here's the App.xaml.cs:

public partial class App : Application
{
    public App()
    {
    }

    private void Application_Startup(object sender, StartupEventArgs e)
    {
        new MainWindow().ShowDialog();
    }
}

This works really great one way: My TextBox always displays the content of MySetting when the window is shown.

The other way around doesn't quite work as I intend. What does work, is when the user manually writes into the TextBox.

What doesn't work, is when I programmatically make changes to the TextBox, like this:

textbox.Text = folderBrowserDialog.SelectedPath;

In this case, MySetting doesn't update until the user types into the TextBox.

My current solution is to do this:

Properties.Settings.Default.MySetting = textbox.Text;

But it defeats the point of having a two-way data binding.

What should I do to have data binding work both ways, even when I'm programmatically changing the user control?


Solution

  • But it defeats the point of having a two-way data binding.

    No, not really.

    The point of two-way binding is so that when the code modifies the source property the UI's target property is updated, and when the user modifies the target property, the source property is updated.

    Two-way binding is definitely not there so that you can assign a value programmatically to the target property and have it reflected in a source property that you could have and should been setting instead.

    It should be very rare for someone writing WPF code to ever have to name or interact with a UI element defined in XAML. And when that does happen, it should be only to implement user interface features, such as drag-select, drag & drop, key handling, etc.

    Putting it another way: in the MVVM paradigm, the view model data structure is the only thing that non-UI code ought to be dealing with. The binding mechanism provides the mediator between the business logic, represented by the view model (and optionally, a model behind that), and the user interface, represented by the XAML.

    Indeed, typically if you were to set the target property explicitly, it would discard the binding, causing it to not work at all.

    So, the right way to do this is, in the code-behind, to only ever interact with the MySetting property. If you want to update the value shown to the user, then you need to change the code-behind property that is bound to that value.