首页 > 解决方案 > WPF按钮点击需要刷新一个绑定;我该怎么做呢?

问题描述

我有一个按钮:

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

和一个列表框:

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

还有一些标签我想刷新单击按钮时的可见性;这是其中之一:

<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"/>

现在的问题是,当我在ListBox;中选择不同的项目时,标签会刷新它们的可见性。但是,当我单击按钮时,它们不会刷新其可见性,即使单击按钮会影响确定标签是否应在我的转换器中可见的状态。

这是我的转换器的转换方法,以防万一:

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;
}

知道为什么单击按钮后转换器中测试的条件发生变化时我的标签不可见吗?我试过这个无济于事:

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

标签: c#wpfxamldata-binding

解决方案


你应该用 MVVM 来做

工作样本:

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>

代码背后:

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

        DataContext = new MainWindowViewModel();
    }
}

视图模型:

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
    }

推荐阅读