简体   繁体   中英

Enable and focus a disabled control after DP changed value

I have a TextBox that must be enabled only if Counter >= 0 . Also when Counter goes from -1 to 0, the TextBox has to get the keyboard focus.

View:

<Window x:Class="Thingy.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"
        xmlns:local="clr-namespace:Thingy"
        mc:Ignorable="d"
        Title="Not random title" Height="200" Width="250">
    <Grid VerticalAlignment="Center" HorizontalAlignment="Center">
        <Grid.Resources>
            <local:IsNegativeConverter x:Key="IsNegativeConv"/>
            <Style x:Key="BoxStyle" TargetType="TextBox">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Counter, Converter={StaticResource IsNegativeConv}}" Value="True">
                        <!-- Here is the problem =( -->
                        <Setter Property="IsEnabled" Value="False"/> 
                    </DataTrigger>
                </Style.Triggers>
                <Setter Property="Width" Value="90"/>
            </Style>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <Grid Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Label Grid.Column="0" Margin="2">Thingy</Label>
            <TextBox x:Name="ThingyBox" Grid.Column="1" Style="{StaticResource BoxStyle}"/>
        </Grid>
        <Grid Grid.Row="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Button Grid.Column="0" Content="-" Command="{Binding Decrease}" />
            <Label Grid.Column="1" Content="{Binding Counter}" Margin="2"/>
            <Button Grid.Column="2" Content="+" Command="{Binding Increase}" />
        </Grid>
    </Grid>
</Window>

Code-behind:

public partial class MainWindow : Window
{
    public ViewModel ViewModel { get; private set; }
    public MainWindow()
    {
        ViewModel = new ViewModel();
        DataContext = ViewModel;
        ViewModel.OnCounterChanged += OnCounterChanged;
        InitializeComponent();
    }

    private void OnCounterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if ((int)e.OldValue == -1 && (int)e.NewValue == 0)
            ThingyBox.Focus();
    }
}

ViewModel:

public class ViewModel : DependencyObject
{
    public event PropertyChangedCallback OnCounterChanged;

    public int Counter
    {
        get { return (int)GetValue(CounterProperty); }
        set { SetValue(CounterProperty, value); }
    }
    public static readonly DependencyProperty CounterProperty =
        DependencyProperty.Register("Counter", typeof(int), typeof(ViewModel), new PropertyMetadata(-2, CounterChanged));
    private static void CounterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ViewModel vm = (ViewModel)d;
        if (vm.OnCounterChanged != null)
            vm.OnCounterChanged(d, e);
    }

    RelayCommand c_Increase;
    public ICommand Increase
    {
        get
        {
            if (c_Increase == null)
                c_Increase = new RelayCommand(p => this.IncreaseExecute(p), null);

            return c_Increase;
        }
    }
    private void IncreaseExecute(object parameter)
    {
        Counter++;
    }

    RelayCommand c_Decrease;
    public ICommand Decrease
    {
        get
        {
            if (c_Decrease == null)
                c_Decrease = new RelayCommand(p => this.DecreaseExecute(p), null);

            return c_Decrease;
        }
    }
    private void DecreaseExecute(object parameter)
    {
        Counter--;
    }
}

The code does enable and disable the control when the counter goes positive or negative, and if I comment the DataTrigger , the control does get the focus when counter goes from 0 to 1.

Individually they work correctly, but they don't work at the same time. My guess is that the DataTrigger triggers too late, but don't know why.

Why is the DataTrigger executing too late? Or the Focus() going too soon?

How can I make them both work, and if possible maintain the MVVM model?

Using the IsEnabledChanged event handler solves it:

<TextBox x:Name="ThingyBox" IsEnabledChanged="ThingyBox_IsEnabledChanged"/>

private void ThingyBox_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    ((TextBox)sender).Focus();
}

It won't work if there are other agents that enable this ofc, but for the current scenario works =)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM