1

I have a simple WPF application. In the code behind I have an InputFile property like this.

    public string InputFile
    {
        get
        {
            return _inputFile;
        }
        set
        {
            _inputFile = value;
            OnPropertyChanged("InputFile");
        }
    }

Inside the XAML I have a StackPanel like this:

    <StackPanel Orientation="Horizontal" DataContext="{Binding Path=InputFile}">
        <StackPanel.CommandBindings>
            <CommandBinding Command="Open" 
                CanExecute="OpenCanExecute"
                Executed="OpenExecuted" />
            <CommandBinding Command="Select" 
                CanExecute="SelectCanExecute"
                Executed="SelectExecuted" />
        </StackPanel.CommandBindings>
        <TextBox Text="{Binding Path=.}"></TextBox>
        <Button Command="Select">...</Button>
        <Button Command="Open">-></Button>
    </StackPanel>

I need to keep the stackpanel datacontext linked to InputFile to allow the commands functions to access it.

Problem: when InputFile changes, the TextBox is updated but if I type a new value in the Textbox the property InputFile is not updated (setter method is not called). Any idea?

ingram
  • 83
  • 3
  • 1
    Do you need to set the `DataContext` of your `StackPanel` to a string? It would be much better to remove the `DataContext` binding and just bind the `TextBox.Text` to your string, like this: ``. But I suspect your problem is the default `UpdateSourceTrigger` for `TextBox.Text` bindings is `LostFocus`, so your setter won't get called until your TextBox loses focus. Change that to `PropertyChanged` and it should work like you expect. – Rachel Apr 04 '13 at 13:33

4 Answers4

1

You can try the following:

<TextBox Text="{Binding Path=., UpdateSourceTrigger=PropertyChanged}"></TextBox>
Tomtom
  • 9,087
  • 7
  • 52
  • 95
0

You can bind directly to TextBox. What is the point to bind to StackPanel if InputFile is string?

<StackPanel Orientation="Horizontal">
    <TextBox Text="{Binding InputFile}"></TextBox>
</StackPanel>

Edit:

You can bind command by using FindAncestor:

Command="{Binding RelativeSource={RelativeSource FindAncestor, 
AncestorType={x:Type Window}}, Path=DataContext.Select}"

Alternatively you can create custom type similar to this one:

public class InputFileViewModel
{
  string File {get; set;}
  ICommant Select {get; set;}
}

And then bind in TextBox to File property.

Community
  • 1
  • 1
Miłosz Wierzbicki
  • 2,082
  • 1
  • 13
  • 15
  • Like he said, he needs that for the Commands, while i agree your idea would be better. He has a different requirement. – dowhilefor Apr 04 '13 at 14:35
0

If your commands are the main reason to have the DataContext set like this, what about this solution?

<StackPanel Orientation="Horizontal">
    <StackPanel.CommandBindings>
        <CommandBinding Command="Open" 
            CanExecute="OpenCanExecute"
            Executed="OpenExecuted" />
        <CommandBinding Command="Select" 
            CanExecute="SelectCanExecute"
            Executed="SelectExecuted" />
    </StackPanel.CommandBindings>
    <TextBox Text="{Binding InputFile}"></TextBox>
    <Button Command="Select" CommandParameter="{Binding InputFile}">...</Button>
    <Button Command="Open" CommandParameter="{Binding InputFile}">-></Button>
</StackPanel>

if all else fails, this should always work. Its a nasty workaround but it should get the job done:

<Grid x:Name="myGrid">
    StackPanel Orientation="Horizontal" DataContext="{Binding Path=InputFile}">
        <StackPanel.CommandBindings>
            <CommandBinding Command="Open" 
                CanExecute="OpenCanExecute"
                Executed="OpenExecuted" />
            <CommandBinding Command="Select" 
                CanExecute="SelectCanExecute"
                Executed="SelectExecuted" />
        </StackPanel.CommandBindings>
        <TextBox Text="{Binding ElementName=myGrid, Path=DataContext.InputFile}"></TextBox>
        <Button Command="Select">...</Button>
        <Button Command="Open">-></Button>
    </StackPanel>
</Grid>

Like Tomtom already wrote, you might need the UpdateSourceTrigger.

dowhilefor
  • 10,971
  • 3
  • 28
  • 45
0

In your binding you can specify the mode to be two way. This will call your setter when the text box value changes from the UI.

<TextBox Text="{Binding Path=., Mode=TwoWay}"/>
  • [TextBox.Text Property](http://msdn.microsoft.com/en-us/library/system.windows.controls.textbox.text.aspx) binding defaults to [BindsTwoWayByDefault](http://msdn.microsoft.com/en-us/library/system.windows.frameworkpropertymetadata.bindstwowaybydefault.aspx) – Bob. Apr 04 '13 at 15:18
  • Why are you even using bindings like this if you are doing logic in the code behind? You could literally just name your view objects and manipulate them directly in the code behind since the two are partial classes. Maybe an MVVM approach would make more sense for your app if you want robust bindings and logic. – Michael Sanderson Apr 04 '13 at 16:47
  • I need to replicate the stackpanel 10 times and I don't want to customize the command fuctions for each panel. Currently I resolved in creating a custom control :-D – ingram Apr 05 '13 at 13:56