Binding IsEnabled to Text.Length only works one way - wpf

I have a TextBox, which I want to be enabled only if another TextBox has text in it. I am binding the Text.Length property of the first TextBox to the IsEnabled property on the second box. I have also tried binding the Text property of the first box and using a converter to convert to a bool. Both methods result in the second box being enabled when text is entered into the first but when the text is deleted the second box isn't disabled.
I have tried setting NotifyOnSourceUpdated and NotifyOnTargetUpdated to true but neither has any effect.
<TextBox Name="textBox1"/>
<TextBox Name="textBox2" IsEnabled="{Binding ElementName=textBox1, Path=Text.Length}"/>
So my question is what is needed for textBox2 to be disabled when the text in textBox1 is deleted.

This should work -
<TextBox Name="textBox1"/>
<TextBox Name="textBox2">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding Text.Length, ElementName=textBox1}"
Value="0">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
Issue with your code is you are binding IsEnabled bool property to Text.Length property whose type is int. So, either you need to use the converter or do it through triggers as i posted above.

Related

WPF IValueConverter for DataGrid.Cell Tooltip Visibility getting null Value in Convert

XAML for Converter
<ToolTip x:Key="toolTipGridCell" DataContext="{Binding Path=PlacementTarget,
RelativeSource={x:Static RelativeSource.Self}}"
Visibility="{Binding Path=PlacementTarget,
RelativeSource={x:Static RelativeSource.Self},
Converter={StaticResource ContentFitsVisibilityConverter}}">
<TextBlock FontWeight="Bold" Text="{Binding Path=Content.Text}"/>
</ToolTip>
....
<DataGrid ....>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="ToolTip" Value="{StaticResource toolTipGridCell}" />
</Style>
</DataGrid.CellStyle>
I need to either hide or show the tooltip on the cell bases on whether the content of that cell is fully visible given the cell's width.
When I remove the Visibility part of the ToolTip, I get the tool tip with cell contents - so the targeting seems to be correct.
But with the visibility defined as above, when the Convert function gets hit as I mouse over the cell, the first parameter (object value) is null, instead of being the DataGrid.Cell over which the tooltip is showing up.
In the Sample Code you have provided, both the datacontext and the visibility of the Tooltip control are bound to the same property "PlacementTarget". This caused the NullReferenceException. To Resolve this issue, bind datacontext and the visibility to the appropriate property in your viewmodel.

Binding Button IsEnabled to TextBox.CanUndo

I'm trying to bind a button to a textbox's CanUndo property, except that I can't get it to work. I tried a direct binding like
IsEnabled="{Binding CanUndo, ElementName=txtDocument}"
But that didn't work. Button stayed disabled even after typing in textbox which would change the CanUndo property to true.
I also tried
<Button IsEnabled="False" >
<Button.Resources>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding CanUndo, ElementName=txtDocument}" Value="True">
<Setter Property="IsEnabled" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Resources>
<Image Source="/Images/32/undo.png" />
</Button>
I also tried with two separate datatriggers, one for enabled true and one for false, but still didn't work. Am I missing something fundamental? Like maybe this property doesn't raise the required events for binding changes?
Thanks
Set the Button's command property to the ApplicationCommands.Undo command and specify the CommandTarget property to be the TextBox.
The button will set the IsEnabled property based on ApplicationCommands.Undo command CanExecute state. The button will be disabled when CanExecute is false and enabled when CanExecute is true.
<StackPanel>
<TextBox x:Name="txtDocument">Test
</TextBox>
<Button Command="ApplicationCommands.Undo" CommandTarget="{Binding ElementName=txtDocument}" Content="Undo"/>
</StackPanel>

Change Binding Format with Focus

WPF application using MVVM. I have a TextBox whose Text property is bound to a decimal property of the view model. This property represents a currency value. I would like the TextBox to display the data in currency format. To this end, I have set StringFormat to "c" in the Binding. This works as expected.
The problem is that, if SourceUpdateTrigger is PropertyChanged, when the user starts typing, formatting is applied after entering the first character and the caret is then positioned before the character just entered. This means that the next character will be entered before the first instead of after. If SourceUpdateTrigger is LostFocus then the user must shift focus to another control before the OK button is enabled, which occurs after validating the currency field.
What I was hoping to do was handle the GotFocus and LostFocus events, get a reference to the Binding and change its StringFormat property. I have no issue with this in regards to MVVM because it's a purely UI issue. The problem is that an exception was thrown and I was told that the Binding could not be changed after being used.
I've considered various other options, including a custom converter. That didn't work though, because I couldn't work out how to use the ConverterParameter to expose the control's IsFocused property to the converter.
Anyone have any ideas?
You can use a data trigger in a data template to dynamically change your binding for a text box.
<DataTemplate x:Key="DataTemplate1">
<TextBox x:Name="TheTextBox"
Text="{Binding Path=ThePropertyPath, StringFormat={}{0:p0}, UpdateSourceTrigger=PropertyChanged}" />
<DataTemplate.Triggers>
<!-- Set the TextBox.Text Binding but this time leave the StringFormat off -->
<DataTrigger Binding="{Binding Path=IsKeyboardFocusWithin, ElementName=TheTextBox}" Value="True">
<Setter TargetName="TheTextBox" Property="Text" Value="{Binding Path=ThePropertyPath, UpdateSourceTrigger=PropertyChanged}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsFocused, ElementName=TheTextBox}" Value="True">
<Setter TargetName="TheTextBox" Property="Text" Value="{Binding Path=ThePropertyPath, UpdateSourceTrigger=PropertyChanged}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>

Conditionally changing the Foreground of a WPF ComboBox item depending upon a value in the databound ItemsSource item

I have a WPF ComboBox bound to a Collection List<Users>. I have applied a DataTemplate to show the FirstName using a TextBlock and this works as expected:
<ComboBox Margin="5" ItemsSource="{Binding Path=TheUsers}" Name="cboUsers">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Margin="10" Text="{Binding Path=FirstName}">
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>`
I have an item in my User class called IsActive which is a Boolean value. If true then I want to set the Foreground of the TextBlock to Navy.
I have spent so much time on what should be so easy and looked all over the web but most articles talk about changing the overall colour or binding to another element in the xaml.
I tried implementing a DataTrigger and after an hour removed the code because it was not working. It would not recognise my field name. Does anyone have a very simple guide to how to do this or what would be the best approach?
As you apparently are not dealing with fields after all, this style should do what you want:
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsActive}" Value="True">
<Setter Property="Foreground" Value="Navy"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
It would not recognise my field name.
You cannot bind to fields, end of story.

How Biniding Mode(TwoWay) works?

I was trying out some dummy application just to test binding modes. So, just curious to know how did the binding modes work. I have this xaml code-
<Button x:Name="btn"
Height="20"
Width="200"
VerticalAlignment="Top">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="IsEnabled"
Value="{Binding CanEnable, Mode=TwoWay}" />
<Style.Triggers>
<DataTrigger Binding="{Binding TextChanged}" Value="true">
<Setter Property="IsEnabled"
Value="true" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Here by button IsEanbled is binded to my viemodel property "CanEanble" whose default value is false. Now in my trigger i was listening to "TextChanged" property and setting button IsEnabled to true. Button gets enabled as it should be but the property "CanEnable" did not set to true even the biding mode is set to TwoWay..
Why this is happening??
By setting the value in the trigger you basically remove the binding you previously set in the style setter. Take a closer look at the style. You will notice that you basically you set the property IsEnabled twice. First in the style setter, second in the trigger. It is logical that the second value overrides the previous value.
The desired effect can be achieved from code if you set the value of the dependency property using SetCurrentValue method:
SetCurrentValue(Button.IsEnabledProperty, true);
This way the bindings set on this property will not be removed and it will work as expected.

Resources