将传统事件添加到自定义控件

时间:2016-03-28 00:10:46

标签: c# .net wpf xaml

我一直试图通过大量的谷歌搜索和SO来解决这个问题,但不幸的是我无法解决这个问题。我读的越多,我就越困惑。

我想将自动填充文本框构建为自定义控件。

我的CustomControl:

Array

我的守则背后:

<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"/> 是通过app.xaml加载的外包类库的命名空间。

无论如何,我在asc属性的XAML中获得的问题以及运行代码时的问题:

  

System.InvalidCastException:无法将类型为“System.Reflection.RuntimeEventInfo”的对象强制转换为“System.Reflection.MethodInfo”。

那到底是怎么回事?我想将TextBox.TextChanged转发到自定义控件模板中的AutoCompleteTextBox TextChanged。与TextBox的{​​{1}}相同。

我从https://msdn.microsoft.com/en-us/library/ms752288(v=vs.100).aspx(对于事件)和其他一些SO问题中获取了大部分代码,用于自定义属性的代码。

不确定,问题是什么,我期待着你的帮助。

1 个答案:

答案 0 :(得分:0)

发生异常是因为您尝试将TextChanged字段的值绑定到需要方法引用的属性。它的确实让WPF感到困惑。 :)

只需从XAML中的TextChanged元素中删除TextBox属性:

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

您已经在构造函数中订阅了该事件,这已经足够了。如果您确实想在构造函数中使用TextChanged属性而不是订阅,那么您可以这样做,但是您需要提供一个实际的事件处理程序,例如代码隐藏中的一种方法。该方法只会调用RaiseTextChangedEvent()方法,就像当前事件处理程序一样。它只是它在类中的命名方法而不是在构造函数中声明的匿名方法。

同样的事情适用于其他事件。


也就是说,您可能会重新考虑实施转发的事件。通常,您的控件的Text属性将绑定到某个模型对象的属性,当绑定属性发生更改时,它本身可以做出适当的反应。它不应该在UserControl对象上需要单独的事件来告诉它它的值已经改变。