WPF - TextBox not binding properly when set to readonly - c#

I have TextBox that I'm using to add (only to add and not read) file path into DB. Text property is set when user selects certain file (OpenFileDialog). So, I set it in readonly state and it won't bind properly. When I remove readonly it works fine.
<Button Name="btnAddFile" Content="+" HorizontalAlignment="Left" Width="23" Height="23" Click="AddFilePath"/>
<TextBox Name="tbxFilePath" Height="23" Text="{Binding FilePath}" Width="364" IsReadOnly="True"/>
When I use:
Text="{Binding FilePath, Mode=OneWayToSource}"
it sometimes work but most of the time it doesn't (?!). I could use TextBlock or Label but I would really like to understand what is going on and use TextBox.
I'm using Entity Framework but don't think it does matter.
Question: How can I programmatically add text to TextBox control which is readonly and be able to bind it.
EDIT: I figured out what the problem is. When I set focus on TextBox after I set it's Text property from code-behind, it works. I guess it has to notify that Text is changed when I do it from code-behind. How to do that?

Have you tried using OneWay Binding?
MSDN reads:
OneWay Updates the binding target (target) property when the binding source (source) changes. This type of binding is appropriate if the control being bound is implicitly read-only.
Which I think covers your scenario.
The target is your TextBox Text property and your source is your FilePath property on your ViewModel.
Use:
Text="{Binding FilePath, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
EDIT
This answer assumes you have implemented INotifyPropertyChanged on your ViewModel.
EDIT
The correct binding mode is OneWayToSource. Confirmed by OP.

Related

How to bind an automatically-set parameter in WPF with MVVM

So here's the situation:
I have a label (custom control derviative of it, if it matters), and I need to get its width and height with MVVM. However, if I set either of the parameters to {Binding XXX}, they are no long Auto and thus when I change the font in runtime their size doesn't update.
I read about using ActualWidth/Height, which sounds like just what I need besides the fact that it's not a dependence parameter, thus it seemss like I'd need to break MVVM for it.
Are there any better solutions?
EDIT
Well, the element in XAML looks nothing special. Just a million of bindings.
<local:DraggableLabel
Content="123"
Margin="{Binding Label2Position, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
FontFamily="{Binding Label2Font.Family}"
FontSize="{Binding Label2Font.Size}"
FontWeight="{Binding Label2Font.Weight}"
FontStyle="{Binding Label2Font.Style}"
Foreground="{Binding Path=Label2Color,
UpdateSourceTrigger=PropertyChanged,
Converter={StaticResource ColorToBrushConverter}
}"/>
The default is,
Width="Auto"
which doesn't have to be written explicits, but can (changes nothing). It makes it resize when the font changes. If I set it to
Width="Binding {Label1Width}"
The binding works fine, but I no longer get the auto-adjustment.
Okay, so I found a workaround.
Since I had create a custom control, I was able to create a new DependencyProperty called RealWidth, then I added a OnSizeChanged event that updates it with the value of ActualWidth that you CAN get from inside the element every time the size of the element changes.

How to control when TextBox Text as binding source updates the target value?

Trying for a simple thing. I want TextBlock text to be updated to what TextBox's text value is. However, I want it to happen only on LostFocus. Currently below code updates a TextBlock as user is typing into a TextBox. How do we achieve that?
<StackPanel>
<TextBox x:Name="txtQty" />
<TextBlock Text="{Binding ElementName=txtQty, Path=Text}" />
</StackPanel>
I explored the UpdateSourceTrigger property on textbox with LostFocus, but it won't work as that controls how the source should be updated, whereas here I need how the destination updates.
I prefer to have a XAML only solution.
XAML is a markup language.
The straight-forward way to to this would be to bind the TextBox and the TextBlock to the same view model source property. The source property will be set when the TextBox loses focus and then the TextBlock will then be updated provided that the view model class implements the INotifyPropertyChanged interface as expected.
You could of course also handle the LostKeyboardFocus event for the TextBox and set the Text property of the TextBlock programmatically in the code-behind of the view. This approach is not any worse than trying to implement some logic in the XAML markup of the very same view. Just because you possibly can do something in pure XAML, it doesn't mean that you always should. A programming language such as C# usually does a better job implementing some logic.
As others already said, the best way would be to bind the TextBlock and the TextBox to the same viewmodel property.
If you want to do it only with XAML code you could try it from the other side and bind your TextBox to the TextBlock.
Like this:
<StackPanel>
<TextBox Text="{Binding ElementName=txtQty, Path=Text, UpdateSourceTrigger=LostFocus, Mode=OneWayToSource}" />
<TextBlock x:Name="txtQty" />
</StackPanel>

How to bind different properties to SelectedItem and SelectedIValue of ComboBox?

I have a thread that updates the current Mode property every second. I also want an option to be able to set a mode within the same cell in datagrid. So, in not editing mode I just show the mode. In editing mode, I show a populated ComboBox.
Now,
to be able to show the selected item in ComboBox, when I enter the editing mode, I bind the SelectedItem to Mode.
to be able to get the changes back to the ViewModel I bind SelectedValue to a different property. ( I need to bind to a different property since 'Mode' is updated every second and will overwrite the selected value).
The problem is that though SelectedItem is bound with Mode=OneTime it still triggers SelectedValue property. I want the SelectedValue to be triggered only when user select a value.
I hope it's clear what I'm trying to do. So, how I can achieve this? Other approaches are welcome (even if I need to use a different control).
<DataGridTemplateColumn Header="Mode">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Mode}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Source={StaticResource Modes}}"
SelectedItem="{Binding Mode, Mode=OneTime}"
SelectedValue="{Binding ModeToSet, Mode=OneWayToSource}"
/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
The premise of what needs to be done is not attainable due to the way the combobox works and how Mode is constantly changing in the background.
Why?
The problem is that though SelectedItem is bound with Mode=OneTime it
still triggers SelectedValue property.
As it should. OneTime as per the docs (BindingMode Enumeration) states:
"Updates the binding target when the application starts or when the data context changes."
The data context as per your design is always changing once a second. If one reads farther into the description it states
"This type of binding is appropriate if you are using data where either a snapshot of the current state is appropriate to use or the data is truly static. ... This is essentially a simpler form of OneWay binding..."
And if one reads up on OneWay bindings
"Updates the binding target (target) property when the binding source (source) changes. This type of binding is appropriate if the control being bound is implicitly read-only."
A combo box is ultimately designed to change both SelectedItem and to get the value off of SelectedItem into SelectedValue
I want the SelectedValue to be triggered only when user select a value.
The problem is not going out of the control, it is what is coming in....
Create a test project and the combobox behaves the way you specify, selected value is only triggered when a user selects a value. Comboboxes only sets the SelectedX properties when a choice is made or an outside value has changed one so it changes the other.
Since Mode is constantly changing it is pushing the change into the selection, not visa versa.
Suggestion To Fix
I suggest you take a snapshot of mode and place that into a ModeOnEdit variable and bind that. When the user makes the selection, capture the event and change the actual Mode.
Test Project
Bind to your own data source, mine was Ships. Ships is a list with and Name as a property on that object. ToString on the ship object returns Name.
Here is the result, there are two textboxes which show the state of the selected item/value. A button to set the selected value and the combobox itself.
<Label Grid.Row="1" Grid.Column="1">SelectedItem</Label>
<TextBlock Grid.Row="1" Grid.Column="2" Text="{Binding SelectedItem, ElementName=cbMain}"/>
<Label Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2">SelectedValue</Label>
<TextBlock Grid.Row="3" Grid.Column="2" Text="{Binding SelectedValue, ElementName=cbMain}"/>
<Button Grid.Row="5" Grid.Column="1" Click="ChangeSelectedValue">Set Selected Value</Button>
<ComboBox Name="cbMain"
Grid.Row="5"
Grid.Column="2"
ItemsSource="{Binding Ships}"
SelectedValuePath="Name"/>
-- Code behind
private void ChangeSelectedValue(object sender, RoutedEventArgs e)
{
cbMain.SelectedValue = "Pacific Silver";
}

WPF Activate binding OnTextInput on textbox

I have a textbox with the following binding :
<TextBox Binding={Path=MyStr, Mode=TwoWay}>
My problem is that the binding only fires when the textbox loses focus and not for each char the user enters.
The textbox also has an OnTextInput function that fires properly but how do I activate the binding in the code behind?
*I'd rather doing it in a pure mvvm way (not use the window's code behind if possible)
Any answer will be accepted mvvm or not.
Here:
<TextBox Text="{Binding Path=MyStr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
now your bound property will be changed on each character.
U can use the updatesource trigger and set it to property changed
<Binding Source="{StaticResource myDataSource}" Path="Name"
UpdateSourceTrigger="PropertyChanged"/>
The moment it is changed it will sent it's updated value back to your DataContext
on msdn:
http://msdn.microsoft.com/en-us/library/system.windows.data.updatesourcetrigger.aspx
There is a UpdateSourceTrigger Called PropertyChanged, if you use that as your update trigger when you change the text of the textbox it will fire and in your binding property setter you can perform what ever action you need to happen as text changes.
<TextBox Text="{Binding Path=Text,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />

Why am i using UpdateSourceTrigger=PropertyChanged ,TwoWay is not enough?

hi; there are Source and target textbox txttarget has a binding to txtsource. when writing something in txtsource, txttarget is changed.Everything is good. But writing on txttarget, i dont see any changes at txttarget? there is TwoWay mode. Twoway mode is not enough? can i write without using "UpdateSourceTrigger=PropertyChanged"?
<Grid>
<TextBox Height="23" HorizontalAlignment="Left" Margin="155,62,0,0" Name="txtSource" VerticalAlignment="Top" Width="120" />
<TextBox Height="23" HorizontalAlignment="Left"
Text="{Binding ElementName=txtSource,Path=Text,Mode=TwoWay}"
Margin="155,113,0,0" Name="txtTarget" VerticalAlignment="Top" Width="120" />
</Grid>
txtTarget.Text is updated whenever the bound source (txtSource.Text) changes.
The binding mode is TwoWay which means that changes to txtTarget.Text will be reflected to the bound source. When? It depends on the Binding.UpdataSourceTrigger property.
If you want your target binding to update your source binding when changing you must use
Binding.UpdataSourceTrigger = OnPropertyChanged, otherwise you will update the binding source when txtTarget losts focus (default behavior).
The default UpdateSourceTrigger for a TextBox is LostFocus (see Binding.UpdateSourceTrigger). If you do not specify PropertyChanged as the UpdateSourceTrigger, what you type into txtTarget will not be written to txtSource until txtTarget loses focus (that is you tab off of it).

Categories

Resources