Ildar
Ildar

Reputation: 115

Enable/disable Button on TextChanged event of TextBox in WPF by XAML

There are TextBox and Button controls in WPF:

<TextBox Name="BackUpTextBox" />
<Button  Name="BackUpSave" Content="Save" />

Button BackUpSave must be enabled if a text of BackUpTextBox is changed. I know how to do that by BackUpTextBox TextChanged event by C# code. But is there a way to enable/disable button by XAML notation?

Upvotes: 0

Views: 5459

Answers (2)

Rohit Vats
Rohit Vats

Reputation: 81233

You can achieve that via EventTrigger. Wrap both controls in StackPanel so that TextChanged events routed upto its parent StackPanel.

And in that case enable Button by setting IsEnabled to True.

<StackPanel>
   <TextBox x:Name="BackUpTextBox"/>
   <Button x:Name="BackUpSave" Content="Save" IsEnabled="False"/>
   <StackPanel.Triggers>
      <EventTrigger RoutedEvent="TextBox.TextChanged">
         <BeginStoryboard>
           <Storyboard>
            <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsEnabled"
                                            Storyboard.TargetName="BackUpSave">
                <DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True"/>
            </BooleanAnimationUsingKeyFrames>
           </Storyboard>
        </BeginStoryboard>
     </EventTrigger>
     <EventTrigger RoutedEvent="Button.Click">
       <BeginStoryboard>
         <Storyboard>
          <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsEnabled"
                                          Storyboard.TargetName="BackUpSave">
                 <DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="False"/>
          </BooleanAnimationUsingKeyFrames>
         </Storyboard>
       </BeginStoryboard>
     </EventTrigger>
     <EventTrigger RoutedEvent="Loaded">
       <BeginStoryboard>
         <Storyboard>
          <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsEnabled"
                                          Storyboard.TargetName="BackUpSave">
                 <DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="False"/>
          </BooleanAnimationUsingKeyFrames>
         </Storyboard>
       </BeginStoryboard>
     </EventTrigger>
  </StackPanel.Triggers>
</StackPanel>

UPDATE

In case you want to disable button on button click again, add another event handler for Button.Click and set it to disable from that. I have updated the xaml code for that.


UPDATE 2

Solution looks such cumbersome that I have big doubt if it worth compared to just setting IsEnabled property in Initial, TextChanged and Click events. Am I missed something that XAML style more preferable these days?

Yes, i have to agree with that XAML only solutions are sometimes cumbersome which can easily be done using code behind. Specifically in your case it could have been done simply by hooking onto some events and more importantly that's not violating any MVVM rules since you are doing view specific things in code behind. So, i see no harm in doing ti from code behind.

XAML only solutions i would generally prefer in cases where i want to store my XAML loosely in some text file and want to load that at runtime using XamlReader.Load().

And as i mentioned animation has higher precedence over local values setter for Dependency property. So, once TextChanged event gets raised value gets set to true and any further change to that property from code behind won't work.

But anyhow you can change that from code behind by setting it via animation (will post here just for completeness of answer and might help others who stumble upon this post). This is how you do it from code behind:

private void Button_BackUpSave_Click(object sender, RoutedEventArgs e)
{
   EnableDisableBackUpSaveButton(false);
}

private void EnableDisableBackUpSaveButton(bool value)
{
   BooleanAnimationUsingKeyFrames animation = 
                              new BooleanAnimationUsingKeyFrames();
   DiscreteBooleanKeyFrame keyFrame = new DiscreteBooleanKeyFrame(value, 
                           KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0)));
   animation.KeyFrames.Add(keyFrame);
   BackUpSave.BeginAnimation(Button.IsEnabledProperty, animation);
}

Now, in XAML you can only have single XAML trigger on TextChanged.

Upvotes: 3

Mark Feldman
Mark Feldman

Reputation: 16119

You can use a data trigger:

<TextBox Name="BackUpTextBox" />
    <Button  Name="BackUpSave" Content="Save">
        <Button.Style>
            <Style TargetType="{x:Type Button}">
                <Setter Property="IsEnabled" Value="True" />
                <Style.Triggers>
                    <DataTrigger Binding="{Binding ElementName=BackUpTextBox, Path=Text, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" Value="{x:Null}">
                        <Setter Property="IsEnabled" Value="False" />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding ElementName=BackUpTextBox, Path=Text, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" Value="">
                        <Setter Property="IsEnabled" Value="False" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
    </Button>

In a real-world application though you wouldn't do this in XAML because there'd be no way to test this behavior in your unit tests.

Upvotes: 2

Related Questions