我有一个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"/>
答案 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;下找到它。扩展。