绑定到自定义控件的一部分中的事件 [英] Bind to event in part of a custom control

查看:17
本文介绍了绑定到自定义控件的一部分中的事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在以下位置实现示例:

I'm trying to implement the example at:

https://github.com/olohmann/WpfRxControls

自定义控件分为三个部分:

There are three parts to the custom control:

PART_TextBox

PART_TextBox

PART_Popup

PART_ListBox

PART_ListBox

相关来源:

https://github.com/olohmann/WpfRxControls/blob/master/WpfRxControls/AutoCompleteTextBox.cs

https://github.com/olohmann/WpfRxControls/blob/master/WpfRxControls/Themes/Generic.xaml

所有的部分都到位了,使用新控件的代码如下:

All the pieces are in place, and the code using the new control is as follows:

<ctrls:AutoCompleteTextBox
            Grid.Row="1"
            AutoCompleteQueryResultProvider="{Binding AutoCompleteQueryResultProvider}"
            Margin="10" FontSize="20" PopupHeight="300">

</ctrls:AutoCompleteTextBox>

我只需要在我的页面 XAML/ViewModel 中挂钩到 ListBox 的 SelectionChanged 事件,这如何实现?

I just need to hook into the ListBox's SelectionChanged event in my pages XAML / ViewModel, how can this be accomplished?

在 XAML/VM 中,不查看后面的代码.到目前为止,所有隐藏的视图代码都是空的,我想保持这种状态.

In XAML / VM, not view code behind. Thus far all view code behinds are empty and I'd like to keep it that way.

我认为有什么方法可以覆盖 MainWindow.XAML 中 ControlTemplate 覆盖中的 PART_ListBox?

I thought there was some way to override PART_ListBox in a ControlTemplate override in MainWindow.XAML?

最终解决方案,感谢 mm8

在 AutoCompleteTextBox.cs 中,创建 ICommand 类型的依赖属性:

In the AutoCompleteTextBox.cs, create a dependency property of type ICommand:

public const string AutoCompleteSelectionChangedPropertyName = "AutoCompleteSelectionChangedCommand";

        public ICommand AutoCompleteSelectionChangedCommand
        {
            get { return (ICommand) GetValue(AutoCompleteSelectionChangedProperty); }
            set { SetValue(AutoCompleteSelectionChangedProperty, value);}
        }

        public static readonly DependencyProperty AutoCompleteSelectionChangedProperty = DependencyProperty.Register(
            AutoCompleteSelectionChangedPropertyName,
            typeof(ICommand),
            typeof(AutoCompleteTextBox));

在 SetResultText 方法中:

In the SetResultText method:

AutoCompleteSelectionChangedCommand?.Execute(autoCompleteQueryResult);

视图/ViewModel 用法:

View / ViewModel usage:

<ac:AutoCompleteTextBox Name="AutoComplete" 
    AutoCompleteQueryResultProvider="{Binding AutoCompleteQueryResultProvider}" 
    FontSize="12"
    AutoCompleteSelectionChangedCommand="{Binding CommandEditValueChanged}">
</ac:AutoCompleteTextBox>


public ICommand CommandEditValueChanged { get; set; }

public MainWindowViewModel(){
     CommandEditValueChanged = new DelegateCommand<object>(OnEditValueChanged);
}

private void OnEditValueChanged(object result){
     // do stuff
}

推荐答案

您可以在视图中处理 AutoCompleteTextBox 的 Loaded 事件,使用 FindName 方法获取对控件模板中的 PART_ListBox 的引用,然后挂钩一个事件ListBox 的 SelectionChanged 事件的处理程序:

You could handle the Loaded event of the AutoCompleteTextBox in the view, get a reference to the PART_ListBox in the control template using the FindName method and then hook up an event handler for the SelectionChanged event of the ListBox:

<ctrls:AutoCompleteTextBox
            Grid.Row="1"
            AutoCompleteQueryResultProvider="{Binding AutoCompleteQueryResultProvider}"
            Margin="10" FontSize="20" PopupHeight="300" Loaded="AutoCompleteTextBox_Loaded">

</ctrls:AutoCompleteTextBox>

<小时>

private void AutoCompleteTextBox_Loaded(object sender, RoutedEventArgs e)
{
    AutoCompleteTextBox actb = sender as AutoCompleteTextBox;
    ListBox lb = actb.Template.FindName("PART_ListBox", actb) as ListBox;
    if (lb != null)
    {
        lb.SelectionChanged += (ss, ee) =>
        {
            MainWindowViewModel vm = DataContext as MainWindowViewModel;
            //invoke a command of the view model or do whatever you want here...
            var selectedItem = lb.SelectedItem;
        };
    }
}

您的视图模型类没有(也不应该有)关于作为控件模板一部分的 ListBox 的参考或知识.

Your view model class has no (and shouldn't have any) reference nor knowledge about the ListBox that is part of the template of the control.

我认为有什么方法可以覆盖 MainWindow.XAML 中 ControlTemplate 覆盖中的 PART_ListBox?

I thought there was some way to override PART_ListBox in a ControlTemplate override in MainWindow.XAML?

然后您将不得不覆盖/重新定义整个 AutoCompleteTextBox 控件的 ControlTemplate,这似乎有点不必要.

Then you will have to override/re-define the entire ControlTemplate of the AutoCompleteTextBox control which seems a bit unnecessary.

MVVM 不是关于从视图中消除代码 - 它是关于关注点的分离,以及您是否从视图的 XAML 标记或完全相同的视图的代码隐藏中连接事件处理程序就设计模式而言,完全没有区别.

MVVM is not about eliminating code from the views - it's about separation of concerns and whether you hook up an event handler from the XAML markup of the view or the code-behind of the very same view makes no difference at all as far as the design pattern is concerned.

但是如果你想保持代码隐藏类的干净,你可以使用附加的行为来实现它:

But if you want to keep the code-behind classes clean you could implement this using an attached behaviour:

public class AutoCompleteBoxBehavior
{
    public static ICommand GetSelectionChangedCommand(AutoCompleteTextBox actb)
    {
        return (ICommand)actb.GetValue(SelectionChangedCommandProperty);
    }

    public static void SetSelectionChangedCommand(AutoCompleteTextBox actb, ICommand value)
    {
        actb.SetValue(SelectionChangedCommandProperty, value);
    }

    public static readonly DependencyProperty SelectionChangedCommandProperty =
        DependencyProperty.RegisterAttached(
        "SelectionChangedCommand",
        typeof(ICommand),
        typeof(AutoCompleteBoxBehavior),
        new UIPropertyMetadata(null, OnHandleSelectionChangedEvent));

    private static void OnHandleSelectionChangedEvent(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ICommand command = e.NewValue as ICommand;
        if(command != null)
        {
            AutoCompleteTextBox actb = d as AutoCompleteTextBox;
            actb.Loaded += (ss, ee) =>
            {
                ListBox lb = actb.Template.FindName("PART_ListBox", actb) as ListBox;
                if (lb != null)
                {
                    lb.SelectionChanged += (sss, eee) =>
                    {
                        command.Execute(null);
                    };
                }
            };
        }
    }
}

<小时>

<ctrls:AutoCompleteTextBox
        Grid.Row="1"
        AutoCompleteQueryResultProvider="{Binding AutoCompleteQueryResultProvider}"
        Margin="10" FontSize="20" PopupHeight="300"
        local:AutoCompleteBoxBehavior.SelectionChangedCommand="{Binding YourCommand}">
 </ctrls:AutoCompleteTextBox>

WPF 中的附加行为简介: https://www.codeproject.com/Articles/28959/Introduction-to-Attached-Behaviors-in-WPF

这篇关于绑定到自定义控件的一部分中的事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆