绑定到自定义控件的一部分中的事件
Bind to event in part of a custom control
我正在尝试在以下位置实施示例:
https://github.com/olohmann/WpfRxControls
自定义控件分为三个部分:
PART_TextBox
PART_Popup
PART_ListBox
相关来源:
https://github.com/olohmann/WpfRxControls/blob/master/WpfRxControls/AutoCompleteTextBox.cs
https://github.com/olohmann/WpfRxControls/blob/master/WpfRxControls/Themes/Generic.xaml
万事俱备,使用新控件的代码如下:
<ctrls:AutoCompleteTextBox
Grid.Row="1"
AutoCompleteQueryResultProvider="{Binding AutoCompleteQueryResultProvider}"
Margin="10" FontSize="20" PopupHeight="300">
</ctrls:AutoCompleteTextBox>
我只需要在我的页面 XAML / ViewModel 中连接到 ListBox 的 SelectionChanged 事件,如何实现?
编辑:在XAML / VM 中,不查看后面的代码。到目前为止,所有视图背后的代码都是空的,我想保持这种状态。
我认为有一些方法可以在 MainWindow.XAML?
中的 ControlTemplate 覆盖中覆盖 PART_ListBox
编辑:最终解决方案,感谢 mm8
在 AutoCompleteTextBox.cs 中,创建 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 方法中:
AutoCompleteSelectionChangedCommand?.Execute(autoCompleteQueryResult);
View/ViewModel 用法:
<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 事件挂接一个事件处理程序:
<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;
};
}
}
您的视图模型 class 没有(也不应该有任何)关于作为控件模板一部分的列表框的参考或知识。
I thought there was some way to override PART_ListBox in a ControlTemplate override in MainWindow.XAML?
那么您将不得不override/re-define 整个 AutoCompleteTextBox 控件的ControlTemplate,这似乎有点不必要。
MVVM 不是 关于从视图中删除代码 - 它是关于关注点分离以及是否从视图的 XAML 标记或就设计模式而言,相同视图的 code-behind 没有任何区别。
编辑: 但是如果你想保持 code-behind classes 干净,你可以使用附加行为来实现它:
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
我正在尝试在以下位置实施示例:
https://github.com/olohmann/WpfRxControls
自定义控件分为三个部分:
PART_TextBox
PART_Popup
PART_ListBox
相关来源:
https://github.com/olohmann/WpfRxControls/blob/master/WpfRxControls/AutoCompleteTextBox.cs
https://github.com/olohmann/WpfRxControls/blob/master/WpfRxControls/Themes/Generic.xaml
万事俱备,使用新控件的代码如下:
<ctrls:AutoCompleteTextBox
Grid.Row="1"
AutoCompleteQueryResultProvider="{Binding AutoCompleteQueryResultProvider}"
Margin="10" FontSize="20" PopupHeight="300">
</ctrls:AutoCompleteTextBox>
我只需要在我的页面 XAML / ViewModel 中连接到 ListBox 的 SelectionChanged 事件,如何实现?
编辑:在XAML / VM 中,不查看后面的代码。到目前为止,所有视图背后的代码都是空的,我想保持这种状态。
我认为有一些方法可以在 MainWindow.XAML?
中的 ControlTemplate 覆盖中覆盖 PART_ListBox编辑:最终解决方案,感谢 mm8
在 AutoCompleteTextBox.cs 中,创建 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 方法中:
AutoCompleteSelectionChangedCommand?.Execute(autoCompleteQueryResult);
View/ViewModel 用法:
<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 事件挂接一个事件处理程序:
<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;
};
}
}
您的视图模型 class 没有(也不应该有任何)关于作为控件模板一部分的列表框的参考或知识。
I thought there was some way to override PART_ListBox in a ControlTemplate override in MainWindow.XAML?
那么您将不得不override/re-define 整个 AutoCompleteTextBox 控件的ControlTemplate,这似乎有点不必要。
MVVM 不是 关于从视图中删除代码 - 它是关于关注点分离以及是否从视图的 XAML 标记或就设计模式而言,相同视图的 code-behind 没有任何区别。
编辑: 但是如果你想保持 code-behind classes 干净,你可以使用附加行为来实现它:
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