簡體   English   中英

如何從DataTemplate引發自定義的路由事件?

[英]How can I raise a custom Routed Event from a DataTemplate?

我有一個名為dCB_Props的用戶控件,其中包含幾個對象,最重要的是一個綁定到Observable集合的ComboBox。 盡管該集合可以使用任何對象,但通常將使用一個稱為EditDeleteItem的UserControl。 我已將dCB_Props設置為使用EditDeleteItem作為ItemsTemplate但未觸發事件。 另一方面,如果我添加EditDeleteItem的實例,則事件將被觸發。 我無法以這種方式添加項目,因為EditDeleteItem將托管其他控件,並且我需要使用其他DataTemplates。

EditDeleteItem具有兩個路由事件,稱為EditClickDeleteClick

當集合更改時,它會觸發一個事件,該事件檢查添加的項是否為EditDeleteItem類型。 如果是這樣,則將處理程序添加到上述兩個事件中。

xaml for EditDeleteClick的一部分:

<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"/>

xaml的dCB_Props的一部分:

<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的項目並刪除EditDeleteItem內的Label的ItemTemplate屬性,則上述方法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放在哪里,也不確定如何使用它們。

謝謝哈桑

事件被觸發,但是您不會捕獲它們,因為如果使用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中的相應命令。

希望我能正確理解您的問題;)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM