TextBox和Button - 绑定和命令

时间:2010-05-19 11:40:49

标签: wpf binding textbox button command

我正在使用MVVM模式。我有一个

  1. Text属性绑定到ViewModel的文本框(V​​M支持INotifyProperyChange)文本属性
  2. 其命令绑定到VM的ICommand属性类型
  3. 的按钮

    您可能会将此视为SearchTextBox和SearchButton

    我面临的问题是,当我在SearchTextBox中输入文本并单击SearchButton时,只会调用SearchTextBox绑定的set属性实现,但SearchButton点击的Command永远不会执行(注意: ICommand CanExecute handler始终返回True)

    如果我使用TAB键跳出SearchTextBox或使用鼠标将焦点从SearchTextBox移开,然后单击SearchButton,它可以正常工作。这意味着要做两个单独的动作来单独触发这两个事件。理想情况下,单击SearchButton会导致SearchTextBox松散焦点,从而调用Set属性,单击“搜索”按钮会转换为命令执行。

    代码如下

    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 :(得分:0)

尝试通过编写一个重现问题的小型测试项目来隔离问题,如果您可以重新发布,请发布代码。通常当你在主项目之外重新解决问题时,问题和解决方案就变得很明显了。

答案 1 :(得分:0)

我创建了一个示例应用程序来重现此问题。

我放置了断点并在SearchText中添加了一个Debug.Writeline - 设置属性和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);
        }
    }

答案 2 :(得分:0)

字节,

对不起我迟到的回复,但我希望无论如何都会变得方便。我最近很忙,所以我无法调试你的代码(当我有更多时间时我会尝试这样做),但请尝试下面粘贴的示例代码(它对我来说非常适合)。你可以看到它非常简单。我使用了你的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}"