简体   繁体   中英

WPF button click needs to refresh a binding; how do I do this?

I have a button:

<Button Grid.Row="2" Grid.Column="0" Command="commands:Commands.BuyComponentCommand" CommandParameter="{Binding ElementName=inventory, Path=SelectedItem}" Click="btnBuy_Click">Buy</Button>

And a list box:

<ListBox Name="inventory" ItemsSource="{Binding Inventory}">
    ...
</ListBox>

And some labels I want to refresh the visibility of when the button is clicked; here's one of them:

<TextBlock Name="txtMineralsWarning" Foreground="Yellow" Text="You don't have enough minerals to buy this component." DataContext="{Binding ElementName=inventory, Path=SelectedItem}" Visibility="{Binding Converter={StaticResource NotEnoughMineralsToVisibilityConverter}}" TextWrapping="Wrap"/>

Now the problem is, the labels refresh their visibility when I select a different item in the ListBox ; however they don't refresh their visibility when I click the button, even though clicking the button can affect the state that determines whether or not the labels should be visible in my converter.

Here's my converter's Convert method, in case it helps:

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    var comp = (Component)value;
    if (comp == null)
        return Visibility.Hidden;
    if (comp.Cost > PlayerShip.Instance.Savings)
        return Visibility.Visible;
    return Visibility.Hidden;
}

Any idea why my labels aren't becoming visible when the condition tested in the converter changes after clicking the button? I tried this to no avail:

private void btnBuy_Click(object sender, RoutedEventArgs e)
{
    txtMineralsWarning.GetBindingExpression(TextBlock.VisibilityProperty).UpdateTarget();
    txtCrewWarning.GetBindingExpression(TextBlock.VisibilityProperty).UpdateTarget();
}

You should do it with MVVM

Working Sample:

XAML:

<Window x:Class="WpfApp4.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:WpfApp4"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <StackPanel>
        <Button Command="{Binding ClickCommand}" Content="Click Me" />
        <TextBlock Text="Label" Visibility="{Binding LabelVisibility}" />
    </StackPanel>
</Window>

Code Behind:

public partial class MainWindow : Window {
    public MainWindow() {
        InitializeComponent();

        DataContext = new MainWindowViewModel();
    }
}

ViewModel:

public class MainWindowViewModel : INotifyPropertyChanged {
        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        public ICommand ClickCommand => new RelayCommand(arg => DoExecuteClickCommand());

        private void DoExecuteClickCommand() {
            if (LabelVisibility == Visibility.Visible) {
                LabelVisibility = Visibility.Collapsed;
            } else {
                LabelVisibility = Visibility.Visible;
            }
            OnPropertyChanged(nameof(LabelVisibility));
        }

        public Visibility LabelVisibility { get; set; }
    }

    public class RelayCommand : ICommand {
        #region Fields

        readonly Action<object> _execute;
        readonly Predicate<object> _canExecute;

        #endregion // Fields

        #region Constructors

        /// <summary>
        /// Creates a new command that can always execute.
        /// </summary>
        /// <param name="execute">The execution logic.</param>
        public RelayCommand(Action<object> execute)
            : this(execute, null) {
        }

        /// <summary>
        /// Creates a new command.
        /// </summary>
        /// <param name="execute">The execution logic.</param>
        /// <param name="canExecute">The execution status logic.</param>
        public RelayCommand(Action<object> execute, Predicate<object> canExecute) {
            if (execute == null)
                throw new ArgumentNullException("execute"); //NOTTOTRANS

            _execute = execute;
            _canExecute = canExecute;
        }

        #endregion // Constructors

        #region ICommand Members

        [DebuggerStepThrough]
        public bool CanExecute(object parameter) {
            return _canExecute == null ? true : _canExecute(parameter);
        }

        public event EventHandler CanExecuteChanged {
            add => CommandManager.RequerySuggested += value;
            remove => CommandManager.RequerySuggested -= value;
        }

        public void Execute(object parameter) {
            _execute(parameter);
        }

        #endregion // ICommand Members
    }

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