简体   繁体   中英

How to update UI in MVVMLight RelayCommand scenario?

Here is a simple screen with one textblock which is "" initially, a button called "Set Text" which sets the text to the textblock and another button called "Clear text" which always clears the text in the textblock . This is how the XAML looks like.

<StackPanel>
    <TextBlock Text="{Binding DisplayText, Mode=TwoWay}"></TextBlock>
    <Button Content="Set Text" Command="{Binding SetTextCommand}"></Button>
    <Button Content="Clear Text" Command="{Binding CancelCommand}" 
                                 IsEnabled="{Binding CanCancel, Mode=TwoWay}"/>
</StackPanel>

Here is my ViewModel code.

public class Page1VM : ViewModelBase
    {

        public RelayCommand SetTextCommand { get; private set; }
        public RelayCommand CancelCommand { get; private set; }

        public Page1VM()
        {
            SetTextCommand = new RelayCommand(HandleSetText, CanExecute);
            CancelCommand = new RelayCommand(HandleClearButtonClick, CanExecuteCancel);
        }

        private void HandleSetText(string number)
        {
            DisplayText = number;
        }

        private string _displayText="";
        public string DisplayText
        {
            get { return _displayText; }
            set
            {
                _displayText = value;
                RaisePropertyChanged("DisplayText");
                RaisePropertyChanged("CanCancel");
            }
        }

        private bool _canCancel;
        public bool CanCancel
        {
            get
            {
                if (DisplayText == "")
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
            set
            {
                _canCancel = value;
                RaisePropertyChanged("CanCancel");
            }
        }

        private bool CanExecute()
        {
            return true;
        }
        private bool CanExecuteCancel()
        {
            if (DisplayText == "")
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        private void HandleClearButtonClick()
        {
            DisplayText = "";
        }
        private void HandleSetText()
        {
            DisplayText = "Hello";
        }
    }

The problem : When the page is loaded, the "Clear text" button is disabled which is expected and works fine as intended.

When i click on "Set Text", i set a text to a textblock by setting a text value to property named DisplayText and also call RaisePropertyChanged("CanCancel"); but even after that my "Clear Text" button is not enabled. What can be the reason behind it ? My textblock shows the text value but the "clear text" button is still not enabled.

There's a bit mixing up going on in your example, as far as I can tell: You basically don't use the built-in 'CanExecute' mechanism of 'RelayCommand', but rebuild it yourself while still defining the CanExecute method of the 'RealyCommand'. The idea of 'CanExecute' is to automatically disbale controls whose command can't execute, so you don't need to do it manually. Returning 'true' in an 'CanExecute' method doesn't really make sense, as you don't necessarily need to have a CanExecute delegate in your RelayCommand ( ... = new RelayCommand(ExecuteCommand); is fine). Your scenario doesn't work because you're not calling 'RaisCanExecuteChanged()' on 'CancelCommand'.

Try the following implementation, I've removed the redundancies and inserted the missing 'RaiseCanExecuteChanged()'. See the comments for explanations:

<StackPanel>
    <TextBlock Text="{Binding DisplayText, Mode=TwoWay}"></TextBlock>
    <Button Content="Set Text" Command="{Binding SetTextCommand}"></Button>
    <Button Content="Clear Text" Command="{Binding CancelCommand}" />
</StackPanel>

And use this simplified ViewModel:

public class Page1VM : ViewModelBase
{
    public RelayCommand SetTextCommand { get; private set; }

    public RelayCommand CancelCommand { get; private set; }

    public Page1VM()
    {
        SetTextCommand = new RelayCommand(ExecuteSetText);

        CancelCommand = new RelayCommand(ExecuteCancel, CanExecuteCancel);
    }

    private string _displayText="";

    public string DisplayText
    {
        get { return _displayText; }
        set
        {
            _displayText = value;
            RaisePropertyChanged("DisplayText");
            RaisePropertyChanged("CanCancel");
            // Raise the CanExecuteChanged event of CancelCommand
            // This makes the UI reevaluate the CanExecuteCancel
            // Set a breakpoint in CanExecuteCancel method to make
            // sure it is hit when changing the text
            CancelCommand.RaiseCanExecuteChanged();                
        }
    }

    private bool CanExecuteCancel()
    {
        // You can simplify the statement like this:
        return DisplayText != "";
    }

    private void ExecuteCancel()
    {
        DisplayText = "";
    }

    private void ExecuteSetText()
    {
        DisplayText = "Hello";
    }
}

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