TextBox и кнопка - привязка и команда - PullRequest
3 голосов
/ 19 мая 2010

Я использую шаблон MVVM. У меня есть

  1. Текстовое поле, свойство Text которого связано с ViewModel (VM поддерживает INotifyProperyChange) Текстовое свойство
  2. Кнопка, команда которой связана с типом свойства виртуальной машины ICommand

Вы можете думать об этом как SearchTextBox и SearchButton

Проблема, с которой я сталкиваюсь, заключается в том, что при вводе текста в SearchTextBox и нажатии SearchButton вызывается только реализация свойства set с привязкой SearchTextBox, но нажатие Command для SearchButton никогда не выполняется (Примечание: ICommand CanExecute handler всегда возвращает True)

Работает нормально, если я либо выхожу из SearchTextBox с помощью клавиши TAB, либо с помощью мыши перемещаю фокус от SearchTextBox, а затем нажимаю кнопку SearchButton. Это означает, что нужно выполнить два отдельных действия, чтобы вызвать оба события по отдельности. В идеале нажатие на SearchButton должно привести к потере фокуса в SearchTextBox, вызывая свойство Set, и щелчок по кнопке Search приводит к выполнению команды.

Код, как показано ниже

XAML:

<TextBox Text="{Binding Path=SearchText,Mode=TwoWay}"/>

<Button Content="Search" Width="100" Command="{Binding MySearchCommand}"/>

C #:

public String _SearchText;
public String SearchText
{
   get { return _SearchText; }
   set 
   {
     _SearchText = value;
     OnPropertyChanged("SearchText"); 
    }
 }

ICommand реализация - это стандартная реализация без причудливого кода, и обработчик CanExecute всегда возвращает True

Ответы [ 3 ]

0 голосов
/ 19 мая 2010

Я создал пример приложения для воспроизведения этой проблемы.

Я установил точку останова и добавил Debug.Writeline в SearchText - Установить свойство и метод MySearchCommandExecute.

Когда установлены точки останова, вызывается только свойство SearchText - Set. Я заметил, что если я удаляю точку останова из свойства SearchText - Set, то и свойство, и команда выполняются правильно. Похоже, некоторые проблемы с VS 2008, но я могу ошибаться.

Соответствующий пример кода, как показано ниже

class SearchViewModel : ViewModelBase
    {
        public SearchViewModel() 
        {

        }

        public String _SearchText;
        public String SearchText
        {
            get { return _SearchText; }
            set
            {
                System.Diagnostics.Debug.WriteLine("Set Membership called");

                OnPropertyChanged("SearchText");
            }
        }

        #region Commands
        RelayCommand _SearchCommand;

        public ICommand SearchCommand
        {
            get
            {
                if (_SearchCommand == null)
                {
                    _SearchCommand = new RelayCommand(param => this.MySearchCommandExecute(), param => this.MySearchCommandCanExecute);
                }
                return _SearchCommand;
            }
        }

        public void MySearchCommandExecute()
        {
            System.Diagnostics.Debug.WriteLine("MySearchCommandExecute called");

            // Do Search
        }

        public bool MySearchCommandCanExecute
        {
            get
            {
                return true;
            }
        }

        #endregion
    }

SearchView.xaml

<UserControl x:Class="WpfApplication2.SearchView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300">
    <StackPanel>
        <StackPanel Orientation="Vertical" HorizontalAlignment="Left" Margin="4">
            <Label Foreground="Black"  FontFamily="Calibri" Width="155" Margin="4,0,4,0" Content="SearchText"/>
            <TextBox Foreground="Black"  FontFamily="Calibri" Width="155" Margin="4,0,4,0" Text="{Binding Path=SearchText}"/>
        </StackPanel>
        <Button HorizontalAlignment="Left" Content="Search" Width="100" Command="{Binding SearchCommand}" Margin="8"/>
    </StackPanel>
</UserControl>

RelayCommand.cs

// Reference: MSDN sample
    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)
        {
            if (execute == null)
                throw new ArgumentNullException("relaycommand execute");

            _execute = execute;
            _canExecute = canExecute;
        }

        [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);
        }
    }
0 голосов
/ 20 мая 2010

байт

Извините за мой поздний ответ, но я надеюсь, что он все равно пригодится. В последнее время я очень занят, поэтому не могу отладить ваш код (я постараюсь сделать это, когда у меня будет больше времени), но, пожалуйста, попробуйте мой пример кода, вставленный ниже (он отлично работает для меня). Как видите, это очень просто. Я использовал ваш xaml, но для Window:

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

        this.DataContext = new TempViewModel();
    }
}

public class TempViewModel : INotifyPropertyChanged
{
    private String _searchText;
    private ICommand _searchCommand;

    #region Commands

    protected class Search : ICommand
    {
        private TempViewModel _viewModel;

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public event EventHandler CanExecuteChanged
        {
            add { }
            remove { }
        }

        public void Execute(object parameter)
        {
            //MessageBox in VM is just for demonstration
            MessageBox.Show("command executed with search string: " + this._viewModel._searchText);
        }

        public Search(TempViewModel viewModel)
        {
            this._viewModel = viewModel;
        }
    }

    #endregion //Commands

    #region INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(String propertyName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion //INotifyPropertyChanged

    #region Public properties

    public String SearchText
    {
        get
        {
            return this._searchText;
        }
        set
        {
            this._searchText = value;
            OnPropertyChanged("SearchText");
        }
    }

    public ICommand SearchCommand
    {
        get
        {
            return this._searchCommand;
        }
        set
        {
            this._searchCommand = value;
            OnPropertyChanged("SearchCommand");
        }
    }

    #endregion //Public properties

    public TempViewModel()
    {
        this.SearchCommand = new Search(this);
        this.SearchText = "Sample string";
    }
}

Пожалуйста, не стесняйтесь спрашивать, есть ли у вас дополнительные вопросы.

РЕДАКТИРОВАТЬ: Ах, извините, но я изменил Command="{Binding SearchCommand}" на Command="{Binding Path=SearchCommand}"

0 голосов
/ 19 мая 2010

Попробуйте изолировать проблему, написав небольшой тестовый проект, который воспроизводит проблему. Если вы можете повторить, пожалуйста, опубликуйте код Обычно, когда вы воспроизводите проблему за пределами основного проекта, проблема и решение становятся очевидными.

...