2016-03-28 95 views
2

我一直試圖找出大量的谷歌搜索和SO,但不幸的是我無法解決這個問題。我讀得越多,我就越困惑。將傳統事件添加到自定義控件

我想建立一個自動完成文本框作爲自定義控件。

我CustomControl:

<UserControl x:Class="ApplicationStyling.Controls.AutoCompleteTextBox" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:local="clr-namespace:ApplicationStyling.Controls" 
      mc:Ignorable="d" 
      d:DesignHeight="300" 
      d:DesignWidth="300" 
      Name="AutoCompleteBox"> 
    <Grid> 
     <TextBox Grid.Row="3" 
       Style="{DynamicResource InputBox}" 
       x:Name="SearchBox" 
       Text="{Binding Text}" 
       TextChanged="{Binding ElementName=AutoCompleteBox, Path=TextChanged}"/> 

     <ListBox x:Name="SuggestionList" 
       Visibility="Collapsed" 
       ItemsSource="{Binding ElementName=AutoCompleteTextBox, Path=SuggestionsSource}" 
       SelectionChanged="{Binding ElementName=AutoCompleteBox, Path=SelectionChanged}"> 
      <ListBox.ItemTemplate> 
       <DataTemplate> 
        <Label Content="{Binding Label}" /> 
       </DataTemplate> 
      </ListBox.ItemTemplate> 
     </ListBox> 
    </Grid> 
</UserControl> 

我的身後代碼:

using System.Collections; 
using System.Windows; 
using System.Windows.Controls; 

namespace ApplicationStyling.Controls 
{ 
    /// <summary> 
    /// Interaction logic for AutoCompleteTextBox.xaml 
    /// </summary> 
    public partial class AutoCompleteTextBox : UserControl 
    { 

     public static readonly DependencyProperty SuggestionsSourceProperty; 
     public static readonly DependencyProperty TextProperty; 

     // Events 
     public static readonly RoutedEvent TextChangedProperty; 
     public static readonly RoutedEvent SelectionChangedProperty; 


     static AutoCompleteTextBox() 
     { 
      // Attributes 
      AutoCompleteTextBox.SuggestionsSourceProperty = DependencyProperty.Register("SuggestionsSource", typeof(IEnumerable), typeof(AutoCompleteTextBox)); 
      AutoCompleteTextBox.TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(AutoCompleteTextBox)); 

      // Events 
      AutoCompleteTextBox.TextChangedProperty = EventManager.RegisterRoutedEvent("TextChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AutoCompleteTextBox)); 
      AutoCompleteTextBox.SelectionChangedProperty = EventManager.RegisterRoutedEvent("SelectionChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AutoCompleteTextBox)); 

     } 

     #region Events 
     public event RoutedEventHandler TextChanged 
     { 
      add { AddHandler(TextChangedProperty, value); } 
      remove { RemoveHandler(TextChangedProperty, value); } 
     } 

     // This method raises the Tap event 
     void RaiseTextChangedEvent() 
     { 
      RoutedEventArgs newEventArgs = new RoutedEventArgs(AutoCompleteTextBox.TextChangedProperty); 
      RaiseEvent(newEventArgs); 
     } 



     public event RoutedEventHandler SelectionChanged 
     { 
      add { AddHandler(SelectionChangedProperty, value); } 
      remove { RemoveHandler(SelectionChangedProperty, value); } 
     } 

     // This method raises the Tap event 
     void RaiseSelectionChangedEvent() 
     { 
      RoutedEventArgs newEventArgs = new RoutedEventArgs(AutoCompleteTextBox.SelectionChangedProperty); 
      RaiseEvent(newEventArgs); 
     } 

     #endregion 

     #region DProperties 
     /// <summary> 
     /// IEnumerable ItemsSource Property for the Suggenstion Box 
     /// </summary> 
     public IEnumerable SuggestionsSource 
     { 
      get 
      { 
       return (IEnumerable)GetValue(AutoCompleteTextBox.SuggestionsSourceProperty); 
      } 
      set 
      { 
       SetValue(AutoCompleteTextBox.SuggestionsSourceProperty, value); 
      } 
     } 

     /// <summary> 
     /// This is the Text attribute which routes to the Textbox 
     /// </summary> 
     public string Text 
     { 
      get 
      { 
       return (string)GetValue(AutoCompleteTextBox.TextProperty); 
      } 
      set 
      { 
       SetValue(AutoCompleteTextBox.TextProperty, value); 
      } 
     } 
     #endregion 

     public AutoCompleteTextBox() 
     { 
      InitializeComponent(); 
      SearchBox.TextChanged += (sender, args) => RaiseTextChangedEvent(); 
      SuggestionList.SelectionChanged += (sender, args) => RaiseSelectionChangedEvent(); 
     } 


    } 
} 

最後,我的方式使用它:

<asc:AutoCompleteTextBox x:Name="ShareAutoCompleteBox" 
           Grid.Row="3" 
           SelectionChanged="ShareAutoCompleteBox_SelectionChanged" 
           TextChanged="ShareAutoCompleteBox_TextChanged"/> 

其中asc是外包類的命名空間通過app.xaml加載的庫。

不管怎麼說,我在TextBox.TextChanged屬性得到在XAML和運行代碼時的問題:

System.InvalidCastException:無法投型「System.Reflection.RuntimeEventInfo」的對象鍵入'System.Reflection.MethodInfo'。

那麼這裏究竟發生了什麼?我想將AutoCompleteTextBox TextChanged轉發到自定義控制模板中的TextBox。與SelectionChangedListbox一樣。

我把大部分代碼從https://msdn.microsoft.com/en-us/library/ms752288(v=vs.100).aspx(用於事件)和其他一些SO問題的自定義屬性的代碼。

不知道,問題是什麼,我期待着您的幫助。

回答

0

發生異常是因爲您試圖將TextChanged字段的值綁定到需要方法引用的屬性。這是真的混淆WPF。 :)

只是刪除從TextBox元素TextChanged屬性,在XAML:

TextChanged="{Binding ElementName=AutoCompleteBox, Path=TextChanged}" 

你已經訂閱到你的構造的情況下,這就足夠了。如果您確實想在構造函數中使用TextChanged屬性而不是訂閱,那麼您可以這樣做,但您需要提供實際的事件處理程序,例如,代碼隱藏中的一種方法。該方法只會調用RaiseTextChangedEvent()方法,就像當前的事件處理程序一樣。它只是它在類中的一個命名方法,而不是在構造函數中聲明的匿名方法。

同樣的事情適用於其他事件。


也就是說,您可能會重新考慮執行轉發的事件。通常情況下,您的控件的Text屬性將被綁定到某個模型對象的屬性,當該綁定屬性發生更改時,該對象本身可以做出適當的反應。它不應該在UserControl對象上需要單獨事件來告訴它它的值已更改。

相關問題