0

我有一个名为的用户控件,dCB_Props其中包含多个对象,最重要的是绑定到可观察集合的组合框。尽管该集合可以采用任何对象,但它通常采用名为 的 UserControl EditDeleteItem。我已设置dCB_PropsEditDeleteItem用作ItemsTemplate但未触发事件。另一方面,如果我添加一个实例,EditDeleteItem那么事件将被触发。我不能以这种方式添加项目,因为 EditDeleteItem 将承载其他控件,并且我需要使用不同的 DataTemplates。

EditDeleteItemEditClick有两个名为和的路由事件DeleteClick

当集合发生变化时,它会触发一个事件,检查添加的项目是否属于 type 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_PropsEditDeleteItem如果我在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 放在哪里,也不太确定如何使用它们,尽管我已经阅读了一两页。

谢谢,哈桑

4

1 回答 1

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 的相应命令。

我希望我正确理解了你的问题;)

于 2012-04-15T18:08:59.720 回答