BooleanToVisibility转换器不适用于数据绑定

问题描述 投票:0回答:1

好,所以我花了数小时试图弄清楚为什么它不起作用。我有几个属性可以毫无问题地从视图模型更新视图。但是,当尝试显示默认情况下处于隐藏状态的按钮时,一旦设置了某个属性,平面便拒绝这样做。我将在下面发布相关代码。

App.xaml

<Application.Resources>
    <BooleanToVisibilityConverter x:Key="BoolToVis" />
</Application.Resources>

GameView.xaml

<StackPanel Orientation="Horizontal">
    <Button Content="Next Round" FontSize="24" Width="165" Margin="5" Height="80" Click="NextRoundButton_Click" Name="NextRound" Visibility="{Binding IsVisible, Converter={StaticResource BoolToVis}, FallbackValue=Hidden}" />
</StackPanel>

GameViewModel.cs

private bool _isVisibile;

public bool IsVisibile
    {
        get => _isVisibile;
        set
        {
            _isVisibile = value;
            OnPropertyChanged(nameof(IsVisibile));
        }
    }

<!-- Farther down in the code during checking of win conditions -->

public void CheckGameWinCondition()
    {
        if (_dealer.CardTotal > 21)
        {
            _gameBoard.currentGameState = GameBoard.GameState.RoundOver;
            _messages = "Dealer Bust";
            _player.TotalWinnings = _player.TotalBet * 2;
            _player.BankRoll += _player.TotalWinnings;
        }
        else if (_dealer.CardTotal == 21)
        {
            _gameBoard.currentGameState = GameBoard.GameState.RoundOver;
            _messages = "Dealer BlackJack";
        }
        else if (_player.CardTotal > _dealer.CardTotal)
        {
            _gameBoard.currentGameState = GameBoard.GameState.RoundOver;
            _messages = "Player Won";
            _player.TotalWinnings = _player.TotalBet * 2;
            _player.BankRoll += _player.TotalWinnings;
        }
        else if (_player.CardTotal < _dealer.CardTotal)
        {
            _gameBoard.currentGameState = GameBoard.GameState.RoundOver;
            _messages = "Dealer Won";
        }
        else if (_player.CardTotal == _dealer.CardTotal)
        {
            _gameBoard.currentGameState = GameBoard.GameState.RoundOver;
            _messages = "Draw";
            _player.TotalWinnings = _player.TotalBet;
            _player.BankRoll += _player.TotalWinnings;
        }
        else 
        {
            _messages = "Error";
            OnPropertyChanged(nameof(Messages));
        }

        _isVisibile = _gameBoard.Visible();

        OnPropertyChanged(nameof(IsVisibile));
        OnPropertyChanged(nameof(Dealer));
        OnPropertyChanged(nameof(Player));
        OnPropertyChanged(nameof(Messages));

    }

这里的错误错误else语句只是存根,而不是最终代码。

GameBoard.cs

 public bool Visible()
        {
            if (currentGameState == GameState.RoundOver)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

所以我有从我的ObservableObject类继承的GameViewModel。这对于我的所有其他绑定都很好,包括在整个UI中切换其他按钮上的IsEnabled。就像我所有其他按钮和事件一样,它也已编码,因此应该可以正常工作。调试显示_isVisible的值已设置为true,因为我在调用GameBoard类中的Visibility()方法返回true或false之前将currentGameState设置为GameBoard.GameState.RoundOver。

它应该进行转换,但不是。我从字面上看了关于此问题的近100条帖子。我已经尝试了遇到的所有内容,尽管OnPropertyChanged()正在按预期方式触发,但没有任何更新。

使用按钮命令不是一种选择,因为这是我为上课而开发的游戏,并且这是我尝试在自己身上添加的一项额外功能。因此,这不是功课,而是游戏正在进行中。我只想隐藏“新回合”按钮,直到回合结束,然后出现它,以便用户可以单击它并开始下一只手。我尝试将转换器也放在Window.Resources下的GameView.xaml中,但仍然无法正常工作。

任何帮助将不胜感激。我们的老师特别希望我们在单击按钮时从ViewModel后面的代码中调用方法,而不是执行命令,以免在学习WPF时使事情变得更复杂。因此,为什么我不希望使用命令,也不想为该项目在这种情况下它们会有所帮助。预先感谢您查看此内容,并希望发现我正在做的一些愚蠢的事情。

如果您需要更多我没有发布的代码的详细信息,可以在我的GitHub https://github.com/petersteele111/WPF_BlackJack上完整查看代码。

c# wpf binding converters
1个回答
0
投票

对于它的价值,我发现使用ICommand对象比将Observable属性绑定到按钮的VisibilityIsEnabled属性要可靠得多。我几乎不再直接绑定IsEnabledVisibility属性。

您将需要this class来实现命令:

/// <summary>
/// Josh Smith's implementation of RelayCommand.  See https://gist.github.com/schuster-rainer/2648922
/// </summary>
public class RelayCommand : ICommand
{
    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;

    public RelayCommand(Action<object> execute) : this(execute, null) { }

    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        _execute = execute ?? throw new ArgumentNullException("execute");
        _canExecute = canExecute;
    }

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

在您的GameViewModel.cs中,放置此端点:

private ICommand _nextRoundCommand;
public ICommand NextRoundCommand
{
    get
    {
        if (_nextRoundCommand== null)
            _nextRoundCommand= new RelayCommand(x => NextRound(), y => IsVisible);
        return _nextRoundCommand;
    }
}

public void NextRound()
{
    // Implementation goes here.
}

然后像这样钩上您的按钮:

<Button
    Name="NextRound"
    Width="165"
    Height="80"
    Margin="5"
    Command="{Binding NextRoundCommand}"
    Content="Next Round"
    FontSize="24"/>

Command对象旨在绑定到按钮的IsEnabled属性。要使按钮在IsVisible属性为false时消失而不是禁用,可以向其中添加this trigger

<Button
    Name="NextRound"
    Width="165"
    Height="80"
    Margin="5"
    Command="{Binding NextRoundCommand}"
    Content="Next Round"
    FontSize="24">
    <Button.Style>
        <Style TargetType="{x:Type Button}" >
            <Style.Triggers>
                <Trigger Property="IsEnabled" Value="False">
                    <Setter Property="Visibility" Value="Collapsed" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </Button.Style>
</Button>
© www.soinside.com 2019 - 2024. All rights reserved.