文本框和按钮 - 绑定和命令

发布于 2024-09-02 06:14:15 字数 1094 浏览 2 评论 0原文

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

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

您可能会将其视为 SearchTextBox 和 SearchButton

我面临的问题是,当我输入SearchTextBox 中的文本并单击 SearchButton,则仅调用 SearchTextBox 绑定的 set 属性实现,但 SearchButton 单击的 Command 永远不会执行(注意:ICommand CanExecute 处理程序 code> 总是返回 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

I am using MVVM pattern. I have a

  1. Text box whose Text property is bound to ViewModel's(VM supports INotifyProperyChange) Text property
  2. Button whose command is bound to VM's ICommand property type

You may think of this as a SearchTextBox and SearchButton

The problem I am facing is that when I enter the text in SearchTextBox and click on SearchButton then only the SearchTextBox bound set property implementation is called but the Command for SearchButton click never executes (Note: ICommand CanExecute handler always returns True)

It works fine if I either tab out of SearchTextBox using TAB key or use mouse to move focus away from SearchTextBox and then click the SearchButton. That means do two seperate actions to trigger both the events seperately. Ideally clicking on the SearchButton should result in the SearchTextBox loose focus thus calling Set property and the click on the Search button translates into the command execution.

Code is as below

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 implementation is a standard implemenetation with no fancy code and CanExecute handler always returns True

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不打扰别人 2024-09-09 06:14:15

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

Try to isolate the issue by writing a small test project that reproduces the issue, if you can repro then please post the code. Usually when you repro the issue outside of your main project the problem and the solution become obvious.

分開簡單 2024-09-09 06:14:15

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

我放置了断点,并在 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);
        }
    }

I created a sample application to reproduce this problem.

I placed breakpoint and added a Debug.Writeline in SearchText - Set property and MySearchCommandExecute method.

When breakpoints are set, only the SearchText - Set property gets called. I observed that if I remove the breakpoint from SearchText - Set property then both the property and the command are correctly executed. Looks like some problem with VS 2008 but I may be wrong.

The relevant sample code is as below

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);
        }
    }
盗梦空间 2024-09-09 06:14:15

字节,

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

Byte,

Sorry for my late response, but I hope it will become handy anyway. I'm very busy lately so I couldn't debug your code (I'll try to do that when I have more time), but please try my sample code pasted below (It works perfectly for me). As you can see it's extremely simple. I used your xaml, but for 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";
    }
}

Please feel free to ask if you have any further questions.

EDIT: Ah, sorry, but I changed Command="{Binding SearchCommand}" to Command="{Binding Path=SearchCommand}"

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文