【问题标题】:TextBox and Button - Binding and Command文本框和按钮 - 绑定和命令
【发布时间】:2011-02-21 08:19:17
【问题描述】:

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

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

你可能认为这是一个 SearchTextBox 和 SearchButton

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

如果我使用 TAB 键从 SearchTextBox 中跳出,或者使用鼠标将焦点从 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

【问题讨论】:

  • CanExecute 运行时你的命令没有执行怎么办?您可以在这里发布实现吗?(您的 Execute 方法)
  • 我认为字节的意思是 CanExecute 没有运行,但被定义为始终返回 true。
  • 肯定有一些愚蠢的错误,请发布您的代码:)
  • 如果问题只是您的 TextBox 仅绑定在 LostFocus 上,那么您可以在绑定中更改此行为,例如 {Binding MyText, UpdateSourceTrigger=PropertyChanged}
  • Piotr - 感谢您的澄清。你的理解是正确的。让我在这里复制代码sn-p

标签: wpf binding textbox button command


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    我在 SearchText - Set 属性和 MySearchCommandExecute 方法中放置了断点并添加了一个 Debug.Writeline。

    设置断点后,仅调用 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);
            }
        }
    

    【讨论】:

      【解决方案3】:

      字节,

      很抱歉我的回复晚了,但我希望它会变得很方便。我最近很忙,所以我无法调试你的代码(当我有更多时间时我会尝试这样做),但请尝试我粘贴在下面的示例代码(它非常适合我)。如您所见,它非常简单。我使用了你的 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}"

      【讨论】:

        猜你喜欢
        • 2017-07-30
        • 2013-10-09
        • 1970-01-01
        • 2019-05-11
        • 1970-01-01
        • 2016-09-09
        • 2013-09-16
        • 2021-07-21
        • 2016-06-25
        相关资源
        最近更新 更多