将click事件添加到wpf中的所有文本框中

时间:2014-09-15 06:42:26

标签: wpf inheritance mvvm textbox

在我的应用程序中,文本框中的所有输入都必须由我自己编写的输入框完成。因此,每当文本框被轻弹时,输入框都会弹出。它看起来像这样:

xaml中的文本框:

<TextBox Text="{Binding Level}" Grid.Row="1" Grid.Column="2" Margin="2">
    <TextBox.InputBindings>
        <MouseBinding Command="{Binding EnterLevel}" MouseAction="LeftClick" />
    </TextBox.InputBindings>
</TextBox>

VM中的命令:

private void ExecuteEnterLevel()
    {
        var dialog = new BFH.InputBox.InputBox("Level", 1, 1, 4);
        dialog.ShowDialog();
        Level = Convert.ToInt16(dialog.Input);
    }

因此输入框的结果将成为输入框的文本。这很好。

现在我的问题是:我可以为所有需要该功能的文本框执行此操作而无需为每个文本框编写事件吗?我想拥有&#34; myTextbox&#34;它自动完成。

到目前为止我尝试了什么: 我的文本框:

class MyTextbox : TextBox
{
    public MyTextbox()
    {
        this.MouseDown += MyTextbox_MouseDown;
    }

    private void MyTextbox_MouseDown(object sender, MouseButtonEventArgs mouseButtonEventArgs)
    {
        TextBox tb = (TextBox)sender;
        var dialog = new BFH.InputBox.InputBox("titel", "input");
        dialog.ShowDialog();
        tb.Text = dialog.Input;
    }
}

和xaml:

<libraries:MyTextbox/>

MyTextbox_MouseDown永远不会执行。我把MessageBox.Show("test")放进其中没有任何结果。我猜我做错了。

1 个答案:

答案 0 :(得分:1)

由于无法在样式中定义InputBindings,至少是以直截了当的方式。我提议使用AttachedProperties

解决问题

让我们首先为附加属性定义一个类

namespace CSharpWPF
{
    class EventHelper 
    {
        public static ICommand GetLeftClick(DependencyObject obj)
        {
            return (ICommand)obj.GetValue(LeftClickProperty);
        }

        public static void SetLeftClick(DependencyObject obj, ICommand value)
        {
            obj.SetValue(LeftClickProperty, value);
        }

        // Using a DependencyProperty as the backing store for LeftClick.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LeftClickProperty =
            DependencyProperty.RegisterAttached("LeftClick", typeof(ICommand), typeof(EventHelper), new PropertyMetadata(null, OnLeftClickChanged));

        private static void OnLeftClickChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            FrameworkElement elem = d as FrameworkElement;
            ICommand command = e.NewValue as ICommand;
            if (command != null)
                elem.InputBindings.Add(new MouseBinding(command, new MouseGesture(MouseAction.LeftClick)));
        }
    }
}

这基本上就是你的代码中的鼠标绑定的翻译已经改变了属性。

使用

<TextBox l:EventHelper.LeftClick="{Binding MyCommand}" />

如果您希望应用于所有TextBox,则将其包含在以TextBox

为目标的通用样式中
<Style TargetType="TextBox">
    <Setter Property="l:EventHelper.LeftClick"
            Value="{Binding MyCommand}" />
</Style>
上面的

l:是指上述声明的类的名称空间,例如xmlns:l="clr-namespace:CSharpWPF"

一个完整的例子

<StackPanel xmlns:l="clr-namespace:CSharpWPF">
    <StackPanel.Resources>
        <Style TargetType="TextBox">
            <Setter Property="l:EventHelper.LeftClick"
                    Value="{Binding MyCommand}" />
        </Style>
    </StackPanel.Resources>
    <TextBox />
    <TextBox />
    <TextBox />
    <TextBox />
</StackPanel>

附加输入框行为

class InputHelper
{
    public static bool GetIsInputBoxEnabled(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsInputBoxEnabledProperty);
    }

    public static void SetIsInputBoxEnabled(DependencyObject obj, bool value)
    {
        obj.SetValue(IsInputBoxEnabledProperty, value);
    }

    // Using a DependencyProperty as the backing store for IsInputBoxEnabled.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty IsInputBoxEnabledProperty =
        DependencyProperty.RegisterAttached("IsInputBoxEnabled", typeof(bool), typeof(InputHelper), new PropertyMetadata(false, OnIsInputBoxEnabled));

    private static void OnIsInputBoxEnabled(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        TextBox tb = d as TextBox;
        if ((bool)e.NewValue)
            tb.PreviewMouseDown += elem_MouseDown;
        else
            tb.PreviewMouseDown -= elem_MouseDown;
    }

    static void elem_MouseDown(object sender, MouseButtonEventArgs e)
    {
        TextBox tb = sender as TextBox;
        var dialog = new BFH.InputBox.InputBox(tb.GetValue(InputBoxTitleProperty), tb.GetValue(InputProperty));
        dialog.ShowDialog();
        tb.Text = dialog.Input;
    }

    public static string GetInputBoxTitle(DependencyObject obj)
    {
        return (string)obj.GetValue(InputBoxTitleProperty);
    }

    public static void SetInputBoxTitle(DependencyObject obj, string value)
    {
        obj.SetValue(InputBoxTitleProperty, value);
    }

    // Using a DependencyProperty as the backing store for InputBoxTitle.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty InputBoxTitleProperty =
        DependencyProperty.RegisterAttached("InputBoxTitle", typeof(string), typeof(InputHelper), new PropertyMetadata(null));

    public static string GetInput(DependencyObject obj)
    {
        return (string)obj.GetValue(InputProperty);
    }

    public static void SetInput(DependencyObject obj, string value)
    {
        obj.SetValue(InputProperty, value);
    }

    // Using a DependencyProperty as the backing store for Input.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty InputProperty =
        DependencyProperty.RegisterAttached("Input", typeof(string), typeof(InputHelper), new PropertyMetadata(null));
}

使用

<TextBox l:InputHelper.IsInputBoxEnabled="true" 
         l:InputHelper.InputBoxTitle="Title"
         l:InputHelper.Input="Input" />

或通过样式

<Style TargetType="TextBox">
    <Setter Property="l:InputHelper.IsInputBoxEnabled"
            Value="true" />
    <Setter Property="l:InputHelper.Title"
            Value="true" />
    <Setter Property="l:InputHelper.Input"
            Value="Input" />
</Style>

使用附加属性可以将此行为附加到现有类,而不是从它们继承。


如果继承文本框类,则可以将两个属性添加到同一个

例如

class MyTextbox : TextBox
{
    public MyTextbox()
    {
        this.PreviewMouseDown += MyTextbox_MouseDown;
    }

    private void MyTextbox_MouseDown(object sender, MouseButtonEventArgs mouseButtonEventArgs)
    {
        TextBox tb = (TextBox)sender;
        var dialog = new BFH.InputBox.InputBox(InputBoxTitle, Input);
        dialog.ShowDialog();
        tb.Text = dialog.Input;
    }

    public string InputBoxTitle { get; set; }

    public string Input { get; set; }
}

使用

<libraries:MyTextbox InputBoxTitle="Title"
                     Input="Input" />