尝试将命令绑定到TextBox时XAML不编译

时间:2013-02-20 15:43:08

标签: c# wpf xaml mvvm

我有一个WPF应用程序(我之前写的相同应用程序),我正在使用Samuel Jack页面http://blog.functionalfun.net/2008/09/hooking-up-commands-to-events-in-wpf.html中显示的事件处理程序。我正在尝试向我的UI中的TextBox添加一个事件处理程序,以执行按下按钮时发生的相同操作。但是,它不会编译,编译错误是这样的:

错误2''Binding'不能在'TextBox'集合中使用。 '绑定'可以 只能在DependencyObject的DependencyProperty上设置。

这是XAML(注意,我希望在TextBox处于焦点时按Enter键的行为与点击按钮时的行为相同:                          

以下是视图模型代码:

/// <summary>
/// The ViewModel in the MVVM pattern
/// </summary>
public class ApplicationViewModel : INotifyPropertyChanged
{
    #region Private members
    private string searchString;
    private string emailString;
    private string toolName;
    private NexusApp selectedApp;
    private ICommand searchButtonCmd;
    private ICommand clearButtonCmd;
    private ICommand emailButtonCmd;
    private ICommand textboxKeyCmd;
    #endregion

    #region INotifyPropertyChanged implementation
    /// <summary>
    /// Notifies the view that the observablecollection bound to the listview has changed
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(string propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    #endregion

    #region Properties
    /// <summary>
    /// Collection bound to listview in ui view
    /// </summary>
    public ObservableCollection<NexusApp> AppCollection { get; set; }

    /// <summary>
    /// The application record selected by user
    /// </summary>
    public NexusApp SelectedApp
    {
        get
        {
            return this.selectedApp;
        }
        set
        {
            this.selectedApp = value;
            this.emailString = this.selectedApp.Email;
            this.toolName = this.selectedApp.Name;
        }
    }

    /// <summary>
    /// String entered by user into search box
    /// </summary>
    public string AppToSearch
    {
        get
        {
            return searchString;
        }
        set
        {
            searchString = value;
        }
    }

    /// <summary>
    /// Email address of team that owns app user is trying to request
    /// </summary>
    public string AppToRequest
    {
        get
        {
            return emailString;
        }
        set
        {
            emailString = value;
        }
    }
    #endregion

    /// <summary>
    /// Default constructor, initialises and populates collection
    /// </summary>
    public ApplicationViewModel()
    {
        this.AppCollection = ApplicationsModel.Current;
    }

    #region Button command handlers
    /// <summary>
    /// Handles search button
    /// </summary>
    public ICommand SearchButtonPressed
    {
        get
        {
            if (this.searchButtonCmd == null)
            {
                this.searchButtonCmd = new RelayCommand(SearchButtonPressedExecute, c => CanSearch);
            }
            return this.searchButtonCmd;
        }
    }

    /// <summary>
    /// Handles clear button
    /// </summary>
    public ICommand ClearButtonPressed
    {
        get
        {
            if (this.clearButtonCmd == null)
            {
                this.clearButtonCmd = new RelayCommand(ClearButtonPressedExecute, c => CanClear);
            }
            return this.clearButtonCmd;
        }
    }

    /// <summary>
    /// Handles Request Application button
    /// </summary>
    public ICommand EmailButtonPressed
    {
        get
        {
            if (this.emailButtonCmd == null)
            {
                this.emailButtonCmd = new RelayCommand(EmailButtonPressedExecute, c => CanEmail);
            }
            return this.emailButtonCmd;
        }
    }

    public ICommand TextBoxKeyPressed
    {
        get
        {
            if (this.textboxKeyCmd == null)
            {
                this.textboxKeyCmd = new RelayCommand(TextBoxKeyPressedExecute, c => CanSearch);
            }
            return this.textboxKeyCmd;
        }
    }

    private void SearchButtonPressedExecute(object parameter)
    {
        try
        {
            ApplicationsModel.Current.Search(this.searchString);
        }
        catch (Exception e)
        {
            string error = String.Format("Could not refresh repository list: {0}", e.Message);
            MessageBox.Show(error, "Error Performing Search", MessageBoxButton.OK, MessageBoxImage.Error);
        }
        NotifyPropertyChanged();
    }

    private void ClearButtonPressedExecute(object parameter)
    {
        try
        {
            this.searchString = String.Empty;
            this.AppToSearch = String.Empty;
            this.AppToSearch = String.Empty;
            ApplicationsModel.Current.ClearSearch();
            NotifyPropertyChanged();
        }
        catch (Exception e)
        {
            string error = String.Format("Could not refresh repository list: {0}", e.Message);
            MessageBox.Show(error, "Error Clearing Search", MessageBoxButton.OK, MessageBoxImage.Error);
        }
    }

    private void EmailButtonPressedExecute(object parameter)
    {
        if (String.IsNullOrEmpty(this.toolName))
        {
            MessageBox.Show("Please select one of the applications to request", "Please select application", MessageBoxButton.OK, MessageBoxImage.Hand);
            return;
        }
        try
        {
            string message;
            if (EmailHelper.IsValidEmail(this.emailString))
            {
                message = String.Format("Request for application {0} successfully sent", this.toolName);
            }
            else
            {
                message = String.Format("Could not send request for access\nThe email address is not defined for tool {0}.\nThe Equity Nexus team has been alerted, asking them to investigate", this.toolName);
            }
            ApplicationsModel.Current.Email(this.emailString, this.toolName);
            MessageBox.Show(message, "Request Sent", MessageBoxButton.OK, MessageBoxImage.Information);
        }
        catch (Exception e)
        {
            string error = String.Format("Could not send application request email, error: {0}", e.Message);
            MessageBox.Show(error, "Erorr sending request", MessageBoxButton.OK, MessageBoxImage.Error);
        }
    }

    private void TextBoxKeyPressedExecute(object parameter)
    {
        MessageBox.Show("Hit textbox event execute");
    }

    /// <summary>
    /// Ability to do search, always true
    /// </summary>
    public bool CanSearch
    { get { return true; } }

    /// <summary>
    /// Ability to clear search, always true
    /// </summary>
    public bool CanClear
    { get { return true; } }

    /// <summary>
    /// Ability to send email, always true
    /// </summary>
    public bool CanEmail
    { get { return true; } }
    #endregion
     }

这是RelayCommand代码:

/// <summary>
/// Hooks up commands to the actions in Button Behaviour class
/// </summary>
public 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("execute");
        }

        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute == null || _canExecute(parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }
}

这是ButtonBehaviour代码:

public static class ButtonBehaviour
{
    public static readonly DependencyProperty SearchCommand;
    public static readonly DependencyProperty ClearCommand;
    public static readonly DependencyProperty EmailCommand;
    public static readonly DependencyProperty TextBoxKeyCommand;

    static ButtonBehaviour()
    {
        SearchCommand = EventBehaviourFactory.CreateCommandExecutionEventBehaviour(Button.ClickEvent, "SearchCommand", typeof(ButtonBehaviour));
        ClearCommand = EventBehaviourFactory.CreateCommandExecutionEventBehaviour(Button.ClickEvent, "ClearCommand", typeof(ButtonBehaviour));
        EmailCommand = EventBehaviourFactory.CreateCommandExecutionEventBehaviour(Button.ClickEvent, "EmailCommand", typeof(ButtonBehaviour));
        TextBoxKeyCommand = EventBehaviourFactory.CreateCommandExecutionEventBehaviour(TextBox.KeyDownEvent, "EnterKeyCommand", typeof(ButtonBehaviour));
    }

    public static void SetSearchCommand(DependencyObject depobj, ICommand value)
    {
        depobj.SetValue(SearchCommand, value);
    }

    public static ICommand GetSearchCommand(DependencyObject depobj)
    {
        return depobj.GetValue(SearchCommand) as ICommand;
    }

    public static void SetClearCommand(DependencyObject depobj, ICommand value)
    {
        depobj.SetValue(ClearCommand, value);
    }

    public static ICommand GetClearCommand(DependencyObject depobj)
    {
        return depobj.GetValue(ClearCommand) as ICommand;
    }

    public static void SetEmailCommand(DependencyObject depobj, ICommand value)
    {
        depobj.SetValue(EmailCommand, value);
    }

    public static ICommand GetEmailCommand(DependencyObject depobj)
    {
        return depobj.GetValue(EmailCommand) as ICommand;
    }

    public static void SetTextBoxKeyCommand(DependencyObject depobj, ICommand value)
    {
        depobj.SetValue(TextBoxKeyCommand, value);
    }

    public static ICommand GetTextBoxKeyCommand(DependencyObject depobj)
    {
        return depobj.GetValue(TextBoxKeyCommand) as ICommand;
    }
}

XAML代码:

                  

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Image Grid.Row="0" Height="84" HorizontalAlignment="Left" Margin="0,5,5,5" Name="imgNexusLogo" Stretch="Fill" VerticalAlignment="Top" Width="600" Source="nexus1bannerlong.png" />
    <Grid Grid.Row="1" HorizontalAlignment="Center" Margin="0,5,5,5" VerticalAlignment="Center">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <Label Grid.Row="0" Grid.Column="0" Content="Search for Application">
            <Label.Foreground>
                <SolidColorBrush Color="LightCyan" />
            </Label.Foreground>
        </Label>
        <TextBox Grid.Row="0" Grid.Column="1" Margin="3" Width="500" Text="{Binding AppToSearch}" vm:ButtonBehaviour.TextBoxKeyCommand="{Binding TextBoxKeyPressed}" />
        <Button Grid.Row="0" Grid.Column="2" HorizontalAlignment="Right" Width="100" Height="20" Margin="3" Background="LightCyan" Content="Search" ToolTip="Click to filter application list by search value" vm:ButtonBehaviour.SearchCommand="{Binding SearchButtonPressed}" />
        <Button Grid.Row="0" Grid.Column="3" HorizontalAlignment="Right" Width="100" Height="20" Margin="3" Background="LightCyan" Content="Clear Search" ToolTip="Click to restore application list to full listing" vm:ButtonBehaviour.ClearCommand="{Binding ClearButtonPressed}"/>
    </Grid>
    <ListView Grid.Row="2" BorderBrush="Black" HorizontalAlignment="Stretch" ItemsSource="{Binding Path=AppCollection}" SelectedItem="{Binding SelectedApp}">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Application Name" Width="200" DisplayMemberBinding="{Binding Name}"/>
                <GridViewColumn Header="Application Description" Width="631" DisplayMemberBinding="{Binding Description}"/>
                <GridViewColumn Header="Application Owner" Width="150" DisplayMemberBinding="{Binding Owner}"/>
            </GridView>
        </ListView.View>
    </ListView>
    <Button Grid.Row="3" HorizontalAlignment="Center" Width="200" Height="30" Margin="3" Background="LightCyan" Content="Request Application" ToolTip="Click here to contact app owners" vm:ButtonBehaviour.EmailCommand="{Binding EmailButtonPressed}" />
</Grid>

可以在http://blog.functionalfun.net/2008/09/hooking-up-commands-to-events-in-wpf.html找到事件行为工厂代码,我没有对其进行任何更改。

任何人都知道我做错了什么?它可能很简单,但由于我是WPF和MVVM的新手,我需要了解它。

谢谢!

跟进

我刚刚做了一个代码并处理了这样的事件。避免任何代码隐藏并不值得所有令人头痛的问题,而且这个项目的最后期限要比MVVM意识形态的纯度更高。对于任何感兴趣的读者,我都是这样做的:

C#代码:

    private void TextBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
    {
        if (e.Key == Key.Enter)
        {
            ApplicationViewModel viewModel = DataContext as ApplicationViewModel;
            if (viewModel != null)
            {
                viewModel.AppToSearch = textboxSearch.Text;
                viewModel.SearchButtonPressedExecute(textboxSearch.Text);
            }
        }
    }

XAML:

    <TextBox Name="textboxSearch" Grid.Row="0" Grid.Column="1" Margin="3" Width="500" Text="{Binding AppToSearch}" KeyDown="TextBox_KeyDown"/>

1 个答案:

答案 0 :(得分:0)

我通常使用触发器将文本框绑定到viewmodel中的命令。

<ComboBox Margin="5" ItemsSource="{Binding Configs}" SelectedItem="{Binding SelectedConfig, Mode=TwoWay}">
      <i:Interaction.Triggers>
          <i:EventTrigger EventName="SelectionChanged">
              <i:InvokeCommandAction  Command="{Binding RetrieveSourceLayersCommand}" />
       </i:EventTrigger>
       </i:Interaction.Triggers>
</ComboBox>

您需要在xaml:xmlns:i =“http://schemas.microsoft.com/expression/2010/interactivity”中添加对此命名空间的引用,并需要在项目引用中添加适当的程序集。在我的情况下,我添加了这个程序集:选择项目&gt;添加参考。在“引用管理器”对话框的“扩展”选项卡上,检查System.Windows.Interactivity的列表。你会在Assemblies&gt;下找到它。扩展。