Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 附加属性/事件_C#_Wpf - Fatal编程技术网

C# 附加属性/事件

C# 附加属性/事件,c#,wpf,C#,Wpf,我有一个关于自定义附加属性/事件的问题。在我的场景中,我希望将属性/事件附加到任何控件。此属性/事件的值应为事件处理程序。简而言之,它应该是这样的: 首先,我尝试将OnDrag实现为一个附加属性。这适用于上述情况,但以下情况失败: 因为“OnDrag”字符串显然不能由XAML系统生成RoutedEventHandler(附加属性的类型) 接下来我尝试使用一个附加的事件,非常像内置的Mouse.MouseEnter 此操作的完整代码显示在底部。在这个版本中发生了一些奇怪的事情: 如果按所示

我有一个关于自定义附加属性/事件的问题。在我的场景中,我希望将属性/事件附加到任何控件。此属性/事件的值应为事件处理程序。简而言之,它应该是这样的:


首先,我尝试将OnDrag实现为一个附加属性。这适用于上述情况,但以下情况失败:


因为“OnDrag”字符串显然不能由XAML系统生成RoutedEventHandler(附加属性的类型)

接下来我尝试使用一个附加的事件,非常像内置的Mouse.MouseEnter

此操作的完整代码显示在底部。在这个版本中发生了一些奇怪的事情:

  • 如果按所示运行代码(注释RegisterRoutedEvent行),它将显示调用了“Add handler”函数。然后,xaml系统在应用样式时会出现内部异常(我猜是由于缺少注册事件)

  • 如果使用RegisterRoutedEvent行运行代码,则所有内容都会运行,但不会调用“Add handler”函数。我希望它被调用,这样我就可以在拖放管理器中注册

  • 奇怪的是,如果我将EventSetter中的事件从我自己的更改为Mouse.MouseEnter,那么xaml设计器(在MainWindow.g[.I].cs中)自动生成的代码就不同了

  • 我不知道为什么2)不给AddXYZHandler打电话。似乎表明这应该有效

    最后,我的问题是:

  • 我怎样才能做到这一点?有可能吗

  • 对于我的场景,我最好使用附加的事件还是附加的属性

  • 对于属性:如何修复样式设置器,使其将OnDrag字符串转换为正确的RoutedEventHandler

  • 如果发生事件:这里出了什么问题?有办法解决这个问题吗?我希望调用AddXYZHandler,但显然这不符合样式

  • MainWindow.xaml:

    
    
    MainWindow.xaml.cs:

    使用System.Windows;
    命名空间网格测试
    {
    公共类XYZTest
    {
    //公共静态只读RoutedEvent XYZEvent=EventManager.RegisterRoutedEvent(“XYZ”,RoutingStrategy.Bubble,typeof(RoutedEventHandler),typeof(XYZTest));
    公共静态void addxyzandler(DependencyObject元素,RoutedEventHandler处理程序)
    {
    Show(“添加处理程序”);
    }
    公共静态void Removexyzandler(DependencyObject元素,RoutedEventHandler处理程序)
    {
    Show(“删除处理程序”);
    }
    }
    公共部分类主窗口:窗口
    {
    公共主窗口()
    {
    初始化组件();
    }
    公共void OnXYZAttached(对象发送方,RoutedEventArgs e)
    {
    MessageBox.Show(“附件”);
    }
    public void OnXYZStyle(对象发送方,RoutedEventArgs e)
    {
    MessageBox.Show(“风格”);
    }
    }
    }
    
    }


    新代码:

    
    
    使用System.Windows;
    命名空间网格测试
    {
    公共类XYZTest
    {
    public static readonly dependencProperty ABCProperty=dependencProperty.RegisterAttached(“ABC”,typeof(RoutedEventHandler),typeof(XYZTest),new UIPropertyMetadata(null,OnABCChanged));
    公共静态void SetABC(UIElement元素,RoutedEventHandler值)
    {
    System.Diagnostics.Debug.WriteLine(“ABC设置为”+value.Method.Name);
    }
    更改后的静态无效(DependencyObject depObj、DependencyPropertyChangedEventArgs e)
    {
    System.Diagnostics.Debug.WriteLine(“ABC更改为”+((RoutedEventHandler)e.NewValue.Method.Name);
    }
    }
    公共部分类主窗口:窗口
    {
    公共主窗口()
    {
    初始化组件();
    DataContext=new[]{“A”、“B”、“C”};
    }
    在XYZtopLevel上公共无效(对象发送方,路由目标)
    {
    MessageBox.Show(“处理程序顶层”);
    }
    public void OnXYZStyle(对象发送方,RoutedEventArgs e)
    {
    Show(“处理程序样式”);
    }
    公共路由EventHandler OnXYZStyleProperty
    {
    获取{return OnXYZStyle;}
    }
    }
    }
    
    我使用
    附加属性成功实现了拖放功能。如果我是你,我会避免为此使用自定义事件,因为你必须使用它们的参数。就个人而言,我选择了
    ICommand
    ,但您也可以使用
    delegate
    s

    请查看下面我在拖放基类实现中使用的属性和
    命令的列表:

    /// <summary>
    /// Gets or sets the type of the drag and drop object required by the Control that the property is set on.
    /// </summary>
    public Type DragDropType { get; set; }
    
    /// <summary>
    /// Gets or sets the allowable types of objects that can be used in drag and drop operations.
    /// </summary>
    public List<Type> DragDropTypes { get; set; }
    
    /// <summary>
    /// Gets or sets the ICommand instance that will be executed when the user attempts to drop a dragged item onto a valid drop target Control.
    /// </summary>
    public ICommand DropCommand { get; set; }
    
    /// <summary>
    /// Gets or sets the DragDropEffects object that specifies the type of the drag and drop operations allowable on the Control that the property is set on.
    /// </summary>
    public DragDropEffects DragDropEffects { get; set; }
    
    /// <summary>
    /// The Point struct that represents the position on screen that the user initiated the drag and drop procedure.
    /// </summary>
    protected Point DragStartPosition
    {
        get { return dragStartPosition; }
        set { if (dragStartPosition != value) { dragStartPosition = value; } }
    }
    
    /// <summary>
    /// The UIElement object that represents the UI element that has the attached Adorner control... usually the top level view.
    /// </summary>
    protected UIElement AdornedUIElement
    {
        get { return adornedUIElement; }
        set { if (adornedUIElement != value) { adornedUIElement = value; } }
    }
    
    然后在扩展的
    ListBoxDragDropManager
    类中:

    protected override void OnAdornedUIElementPreviewDragOver(object sender, DragEventArgs e)
    {
        HitTestResult hitTestResult = VisualTreeHelper.HitTest(AdornedUIElement, e.GetPosition(AdornedUIElement));
        ListBox listBoxUnderMouse = hitTestResult.VisualHit.GetParentOfType<ListBox>();
        if (listBoxUnderMouse != null && listBoxUnderMouse.AllowDrop)
        {
            UpdateDropProperties(ListBoxProperties.GetDragDropType(listBoxUnderMouse), ListBoxProperties.GetDropCommand(listBoxUnderMouse));
        }
        UpdateDragDropEffects(listBoxUnderMouse, e);
        e.Handled = true;  // This bypasses base class behaviour
    }
    

    但是我必须诚实。。。这是一个很大的工作。不过,现在我只需设置几个属性就可以通过视觉反馈实现拖放操作,这似乎完全值得。

    谢谢您的回答。这与我所拥有的类似(不包括Telerik dragdropmanager)。在listbox的情况下,我会为项目使用一种样式。然后你就可以摆脱所有的hitbox测试了。这就是问题所在。我想写一些东西,比如OnXYZStyle只是一个常规的方法处理程序。但当您这样做时,XAML加载程序崩溃。所以我把Value=“{Binding OnXYZStyle,ElementName=root}”放在那里,但是当然我需要一个名为OnXYZStyle的属性,它返回一个委托。如果你使用ICommands,那么你可以通过一个属性返回委托来绕过我原来的问题。
    …DragDropManager
    类是我自己的自定义类,而不是Telerik的。我不是
    protected override void OnAdornedUIElementPreviewDragOver(object sender, DragEventArgs e)
    {
        HitTestResult hitTestResult = VisualTreeHelper.HitTest(AdornedUIElement, e.GetPosition(AdornedUIElement));
        ListBox listBoxUnderMouse = hitTestResult.VisualHit.GetParentOfType<ListBox>();
        if (listBoxUnderMouse != null && listBoxUnderMouse.AllowDrop)
        {
            UpdateDropProperties(ListBoxProperties.GetDragDropType(listBoxUnderMouse), ListBoxProperties.GetDropCommand(listBoxUnderMouse));
        }
        UpdateDragDropEffects(listBoxUnderMouse, e);
        e.Handled = true;  // This bypasses base class behaviour
    }
    
    <ListBox ItemsSource="{Binding Disc.Tracks, IsAsync=True}" SelectedItem="{Binding 
        Disc.Tracks.CurrentItem}" AllowDrop="True" Attached:ListBoxProperties.
        IsDragTarget="True" Attached:ListBoxProperties.DropCommand="{Binding 
        DataContext.DropTracks, RelativeSource={RelativeSource AncestorType={x:Type 
        Views:ReleaseTracksView}}}" Attached:ListBoxProperties.DragDropTypes="{Binding 
        DataContext.DragDropTypes, RelativeSource={RelativeSource AncestorType={x:Type 
        Views:ReleaseTracksView}}}" Attached:ListBoxProperties.DragEffects="{Binding 
        DataContext.DragEffects, RelativeSource={RelativeSource AncestorType={x:Type 
        Views:ReleaseTracksView}}}">