我有一个名为dCB_Props
的用户控件,它包含多个对象,最重要的是一个绑定到Observable Collection的ComboBox。虽然集合可以使用任何对象,但通常会使用名为EditDeleteItem
的UserControl。我已将dCB_Props
设置为使用EditDeleteItem
作为ItemsTemplate
但事件未被触发。另一方面,如果我添加EditDeleteItem
的实例,那么事件将被触发。我无法以这种方式添加项目,因为EditDeleteItem将托管其他控件,我需要使用不同的DataTemplates。
EditDeleteItem
有两个名为EditClick
和DeleteClick
的路由事件。
当集合发生更改时,它会触发一个事件,检查添加的项是否为EditDeleteItem
类型。如果是这样,那么它会为上述两个事件添加处理程序。
EditDeleteClick的部分xaml:
<WrapPanel x:Name="wp" HorizontalAlignment="Right" Visibility="Hidden" VerticalAlignment="Center" Margin="0,0,5,0">
<Button x:Name="PART_Edit" Width="20" Height="20" Content="{DynamicResource dPen}" Style="{DynamicResource dTranspButton}" Click="btnEdit_Click"/>
<Button x:Name="PART_Delete" Width="20" Height="20" Content="{DynamicResource dCross}" Style="{DynamicResource dTranspButton}" Click="btnDelete_Click"/>
</WrapPanel>
<Label Content="{TemplateBinding Content}" Margin="2,0,45,0" Padding="0,0,0,0" HorizontalAlignment="Left" VerticalContentAlignment="Center"/>
dCB_Props的部分xaml:
<ComboBox HorizontalContentAlignment="Stretch" x:Name="PART_cb" Background="Transparent" Margin="0,0,0.367,0" d:LayoutOverrides="HorizontalAlignment" ItemsSource="{Binding Items, ElementName=dcb}" IsDropDownOpen="{Binding IsDropDownOpen,ElementName=dcb, Mode=TwoWay}" Grid.ColumnSpan="3" Style="{DynamicResource DaisyComboBox}" />
<Button x:Name="PART_Edit" Width="20" Height="20" Content="{DynamicResource dPen}" Visibility="Hidden" Style="{DynamicResource dTranspButton}" Margin="2.581,1.48,17.778,-1.48" Grid.Column="1" Click="btnEdit_Click"/>
<Button x:Name="PART_Delete" Width="20" Height="20" Content="{DynamicResource dCross}" Visibility="Hidden" Margin="22.602,1.48,-2.243,-1.48" Style="{DynamicResource dTranspButton}" Grid.Column="1" Click="btnDelete_Click"/>
<Button x:Name="PART_Add" Content="+" Grid.Column="3" Margin="0,0,0,0" Style="{DynamicResource dTranspButton}" Click="btnAdd_Click"/>
注意上面两个是仅用于对象的代码,我遗漏了列定义,事件触发器等。
dCB_Props.xaml.cs代码的一部分是:
public partial class dCB_Props : UserControl
{
public dCB_Props()
{
this.InitializeComponent();
Items= new ObservableCollection<object>();
Items.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Items_CollectionChanged);
}
void Items_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
foreach (var o in e.NewItems)
{
if (o.GetType() == typeof(EditDeleteItem))
{
EditDeleteItem itm = (EditDeleteItem)o;
itm.EditClick += new RoutedEventHandler(ItemEdit_Click);
itm.DeleteClick += new RoutedEventHandler(ItemDelete_Click);
}
}
}
}
...//I've left some code here since I don't deem it's that important for the situation
private void ItemEdit_Click(object sender, RoutedEventArgs e)
{
DependencyObject d = GetTemplateChild("PART_cb");
if (d == null) return;
ComboBox cb = (ComboBox)d;
if (cb.SelectedItem != null) RaiseEvent(new RoutedEventArgs(EditClickEvent, e.OriginalSource));
}
}
如果我添加EditDeleteItem
类型的项目并删除位于ItemTemplate
内的Label的dCB_Props
属性,则上述方法有效。如果我在EditDeleteItem
的ContentTemplate中设置如下所示的ItemTemplate,它也可以工作。但是,如上所述,我需要使用不同的数据模板,因此我假设所有数据模板都必须驻留在资源字典中,然后我必须使用模板选择器。
数据模板:
<DataTemplate x:Shared="false" x:Key="TagTemplate">
<local:EditDeleteItem x:Name="edItem">
<local:EditDeleteItem.Content>
<StackPanel>
<TextBlock Text="{Binding Path=Content.Label}"/>
<CheckBox Content="Isolated" IsChecked="{Binding Content.IsIsolated}"/>
<CheckBox Content="Match Case" IsChecked="{Binding Content.MatchCase}"/>
<CheckBox Content="Include" IsChecked="{Binding Content.Include}"/>
</StackPanel>
</local:EditDeleteItem.Content>
</local:EditDeleteItem>
</DataTemplate>
我相信我需要使用命令绑定。但是不确定在哪里放置CommandBindings,并且不太确定如何使用它们,尽管我已经阅读了一两页。
谢谢, 哈桑
答案 0 :(得分:0)
事件被触发,但你没有捕获它们,因为如果使用ItemTemplate,则不会发生Items_CollectionChanged中的订阅。
您应该了解ItemsControl(和ComboBox)如何与ItemsSource一起使用。 ItemsControl使用ItemContainerGenerator填充其可视树。 ItemsSource中的每个项目都包装到从ContentControl派生的容器中。然后将item设置为Content,将ItemTemplate设置为ContentTemplate,依此类推。当您将EditDeleteItem放入ItemTemplate时,它将成为可视树的一部分,但不是项目的一部分。这就是e.NewItems中没有EditDeleteItem而没有订阅的原因。
正如你所提到的,正确的方法是命令。您应该声明两个命令:
public class EditDeleteItem : UserControl
{
...
public static readonly RoutedUICommand EditCommand = new RoutedUICommand(...);
public static readonly RoutedUICommand DeleteCommand = new RoutedUICommand(...);
...
}
现在,模板的一部分可能如下所示:
<WrapPanel ...>
<Button ... Command="{x:Static EditDeleteItem.EditCommand}"/>
<Button ... Command="{x:Static EditDeleteItem.DeleteCommand}"/>
</WrapPanel>
然后将命令绑定添加到dCB_Props:
public partial class dCB_Props : UserControl
{
static dCB_Props()
{
...
CommandManager.RegisterClassCommandBinding(
typeof(dCB_Props),
new CommandBinding(EditDeleteItem.EditCommand, OnEditCommandExecuted));
CommandManager.RegisterClassCommandBinding(
typeof(dCB_Props),
new CommandBinding(EditDeleteItem.DeleteCommand, OnDeleteCommandExecuted));
...
}
...
}
您需要实现OnEditCommandExecuted和OnDeleteCommandExecuted才能处理来自EditDeleteItem的相应命令。
我希望我能正确理解你的问题;)