Cách thêm Hành vi hòa trộn trong Bộ định kiểu


88

Tôi đã tạo ra một hành vi Blend cho Button. Làm cách nào để đặt điều đó cho tất cả các Nút của tôi trong ứng dụng.

<Button ...>
  <i:Interaction.Behaviors>
    <local:MyBehavior />
  </i:Interaction.Behaviors>
</Button>

Tuy nhiên, khi tôi thử:

<Style>
  <Setter Property="i:Interaction.Behaviors">
    <Setter.Value>
      <local:MyBehavior />
    </Setter.Value>
  </Setter>
</Style>

Tôi nhận được lỗi

Thuộc tính "Behaviors" không có bộ định vị có thể truy cập được.

Câu trả lời:


76

Tôi đã gặp vấn đề tương tự và tôi đã đưa ra giải pháp. Tôi tìm thấy câu hỏi này sau khi tôi giải quyết nó và tôi thấy rằng giải pháp của tôi có rất nhiều điểm chung với của Mark. Tuy nhiên, cách tiếp cận này có một chút khác biệt.

Vấn đề chính là các hành vi và trình kích hoạt liên kết với một đối tượng cụ thể và do đó bạn không thể sử dụng cùng một trường hợp của một hành vi cho nhiều đối tượng liên kết khác nhau. Khi bạn xác định hành vi của mình, XAML nội dòng sẽ thực thi mối quan hệ 1-1 này. Tuy nhiên, khi bạn cố gắng thiết lập một hành vi trong một kiểu, kiểu đó có thể được sử dụng lại cho tất cả các đối tượng mà nó áp dụng và điều này sẽ đưa ra các ngoại lệ trong các lớp hành vi cơ sở. Trên thực tế, các tác giả đã nỗ lực đáng kể để ngăn chặn chúng tôi thậm chí cố gắng làm điều này, biết rằng nó sẽ không hiệu quả.

Vấn đề đầu tiên là chúng ta thậm chí không thể xây dựng một giá trị bộ cài đặt hành vi vì hàm tạo là bên trong. Vì vậy, chúng ta cần các lớp thu thập hành vi và kích hoạt của riêng mình.

Vấn đề tiếp theo là các thuộc tính đính kèm hành vi và trình kích hoạt không có bộ định tuyến và vì vậy chúng chỉ có thể được thêm vào với XAML nội dòng. Vấn đề này chúng tôi giải quyết với các thuộc tính đính kèm của riêng chúng tôi thao tác các hành vi chính và thuộc tính kích hoạt.

Vấn đề thứ ba là bộ sưu tập hành vi của chúng tôi chỉ tốt cho một mục tiêu kiểu duy nhất. Điều này chúng tôi giải quyết bằng cách sử dụng một tính năng XAML ít được sử dụng x:Shared="False"để tạo ra một bản sao mới của tài nguyên mỗi khi nó được tham chiếu.

Vấn đề cuối cùng là các hành vi và trình kích hoạt không giống như các trình thiết lập kiểu khác; chúng tôi không muốn thay thế các hành vi cũ bằng các hành vi mới bởi vì chúng có thể làm những điều cực kỳ khác biệt. Vì vậy, nếu chúng tôi chấp nhận rằng một khi bạn thêm một hành vi mà bạn không thể xóa nó đi (và đó là cách các hành vi hiện đang hoạt động), chúng tôi có thể kết luận rằng các hành vi và trình kích hoạt phải là phụ gia và điều này có thể được xử lý bởi các thuộc tính đính kèm của chúng tôi.

Đây là một ví dụ sử dụng cách tiếp cận này:

<Grid>
    <Grid.Resources>
        <sys:String x:Key="stringResource1">stringResource1</sys:String>
        <local:Triggers x:Key="debugTriggers" x:Shared="False">
            <i:EventTrigger EventName="MouseLeftButtonDown">
                <local:DebugAction Message="DataContext: {0}" MessageParameter="{Binding}"/>
                <local:DebugAction Message="ElementName: {0}" MessageParameter="{Binding Text, ElementName=textBlock2}"/>
                <local:DebugAction Message="Mentor: {0}" MessageParameter="{Binding Text, RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}}"/>
            </i:EventTrigger>
        </local:Triggers>
        <Style x:Key="debugBehavior" TargetType="FrameworkElement">
            <Setter Property="local:SupplementaryInteraction.Triggers" Value="{StaticResource debugTriggers}"/>
        </Style>
    </Grid.Resources>
    <StackPanel DataContext="{StaticResource stringResource1}">
        <TextBlock Name="textBlock1" Text="textBlock1" Style="{StaticResource debugBehavior}"/>
        <TextBlock Name="textBlock2" Text="textBlock2" Style="{StaticResource debugBehavior}"/>
        <TextBlock Name="textBlock3" Text="textBlock3" Style="{StaticResource debugBehavior}"/>
    </StackPanel>
</Grid>

Ví dụ sử dụng trình kích hoạt nhưng các hành vi hoạt động theo cùng một cách. Trong ví dụ, chúng tôi hiển thị:

  • phong cách có thể được áp dụng cho nhiều khối văn bản
  • một số loại liên kết dữ liệu đều hoạt động chính xác
  • một hành động gỡ lỗi tạo ra văn bản trong cửa sổ đầu ra

Đây là một hành vi ví dụ, của chúng tôi DebugAction. Nói đúng hơn nó là một hành động nhưng thông qua việc lạm dụng ngôn ngữ mà chúng ta gọi là hành vi, tác nhân và hành động là "hành vi".

public class DebugAction : TriggerAction<DependencyObject>
{
    public string Message
    {
        get { return (string)GetValue(MessageProperty); }
        set { SetValue(MessageProperty, value); }
    }

    public static readonly DependencyProperty MessageProperty =
        DependencyProperty.Register("Message", typeof(string), typeof(DebugAction), new UIPropertyMetadata(""));

    public object MessageParameter
    {
        get { return (object)GetValue(MessageParameterProperty); }
        set { SetValue(MessageParameterProperty, value); }
    }

    public static readonly DependencyProperty MessageParameterProperty =
        DependencyProperty.Register("MessageParameter", typeof(object), typeof(DebugAction), new UIPropertyMetadata(null));

    protected override void Invoke(object parameter)
    {
        Debug.WriteLine(Message, MessageParameter, AssociatedObject, parameter);
    }
}

Cuối cùng, bộ sưu tập của chúng tôi và các thuộc tính đính kèm để làm cho tất cả điều này hoạt động. Tương tự với Interaction.Behaviors, thuộc tính mà bạn nhắm mục tiêu được gọi SupplementaryInteraction.Behaviorsvì bằng cách đặt thuộc tính này, bạn sẽ thêm các hành vi vào Interaction.Behaviorsvà tương tự như vậy cho các trình kích hoạt.

public class Behaviors : List<Behavior>
{
}

public class Triggers : List<TriggerBase>
{
}

public static class SupplementaryInteraction
{
    public static Behaviors GetBehaviors(DependencyObject obj)
    {
        return (Behaviors)obj.GetValue(BehaviorsProperty);
    }

    public static void SetBehaviors(DependencyObject obj, Behaviors value)
    {
        obj.SetValue(BehaviorsProperty, value);
    }

    public static readonly DependencyProperty BehaviorsProperty =
        DependencyProperty.RegisterAttached("Behaviors", typeof(Behaviors), typeof(SupplementaryInteraction), new UIPropertyMetadata(null, OnPropertyBehaviorsChanged));

    private static void OnPropertyBehaviorsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var behaviors = Interaction.GetBehaviors(d);
        foreach (var behavior in e.NewValue as Behaviors) behaviors.Add(behavior);
    }

    public static Triggers GetTriggers(DependencyObject obj)
    {
        return (Triggers)obj.GetValue(TriggersProperty);
    }

    public static void SetTriggers(DependencyObject obj, Triggers value)
    {
        obj.SetValue(TriggersProperty, value);
    }

    public static readonly DependencyProperty TriggersProperty =
        DependencyProperty.RegisterAttached("Triggers", typeof(Triggers), typeof(SupplementaryInteraction), new UIPropertyMetadata(null, OnPropertyTriggersChanged));

    private static void OnPropertyTriggersChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var triggers = Interaction.GetTriggers(d);
        foreach (var trigger in e.NewValue as Triggers) triggers.Add(trigger);
    }
}

và ở đó bạn có nó, các hành vi và kích hoạt đầy đủ chức năng được áp dụng thông qua các kiểu.


Công cụ tuyệt vời, nó hoạt động tuyệt vời. Tôi nhận thấy rằng nếu bạn đặt kiểu, ví dụ, trong tài nguyên UserControl, thì e.NewValue lúc đầu có thể là null (có thể phụ thuộc vào điều khiển được sử dụng - Tôi đang sử dụng điều này trên XamDataTreeNodeControl trong một XamDataTree của Infragistics). Vì vậy, tôi đã thêm một kiểm tra sanity ít trong OnPropertyTriggersChanged: if (! E.NewValue = null)
MetalMikester

Có ai gặp vấn đề với cách tiếp cận này khi áp dụng Setter theo kiểu ngầm định không? Tôi đã làm cho nó hoạt động tốt với kiểu không ngầm định (một kiểu có Khóa), nhưng tôi nhận được một ngoại lệ tham chiếu theo chu kỳ nếu nó ở kiểu không tường minh.
Jason Frank

1
Thoải mái giải pháp, nhưng tiếc là nó không làm việc trong WinRT, vì x: Shared không tồn tại trên nền tảng này ...
Thomas Levesque

1
Tôi có thể xác nhận rằng giải pháp này hoạt động. Cảm ơn bạn rất nhiều vì đã chia sẻ nó. Mặc dù vậy, tôi vẫn chưa thử nó với một phong cách ngầm.
Golvellius

2
@Jason Frank, Cảm ơn, Chỉ là tài liệu tham khảo cho những người khác ... Tôi đã làm cho nó hoạt động trong cả hai trường hợp: Ngụ ý và rõ ràng. Trên thực tế, tôi hỏi một câu hỏi mà tôi sẽ đặt tất cả mã của mình để giúp những người khác nhưng ai đó ước tính rằng câu hỏi của tôi là trùng lặp. Tôi không thể trả lời câu hỏi của chính mình cho tất cả những gì tôi đã tìm thấy. Tôi nghĩ rằng tôi khám phá ra những điều khá tốt đẹp. :-( ... Tôi hy vọng nó không xảy ra quá thường xuyên vì hành vi tước đoạt những người dùng khác từ các thông tin hữu ích.
Eric Ouellet

27

Tổng hợp các câu trả lời và bài viết tuyệt vời này Blend Behaviors in Styles , tôi đã đi đến giải pháp chung chung ngắn gọn và tiện lợi này:

Tôi đã tạo lớp chung, có thể được kế thừa bởi bất kỳ hành vi nào.

public class AttachableForStyleBehavior<TComponent, TBehavior> : Behavior<TComponent>
        where TComponent : System.Windows.DependencyObject
        where TBehavior : AttachableForStyleBehavior<TComponent, TBehavior> , new ()
    {
        public static DependencyProperty IsEnabledForStyleProperty =
            DependencyProperty.RegisterAttached("IsEnabledForStyle", typeof(bool),
            typeof(AttachableForStyleBehavior<TComponent, TBehavior>), new FrameworkPropertyMetadata(false, OnIsEnabledForStyleChanged)); 

        public bool IsEnabledForStyle
        {
            get { return (bool)GetValue(IsEnabledForStyleProperty); }
            set { SetValue(IsEnabledForStyleProperty, value); }
        }

        private static void OnIsEnabledForStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            UIElement uie = d as UIElement;

            if (uie != null)
            {
                var behColl = Interaction.GetBehaviors(uie);
                var existingBehavior = behColl.FirstOrDefault(b => b.GetType() ==
                      typeof(TBehavior)) as TBehavior;

                if ((bool)e.NewValue == false && existingBehavior != null)
                {
                    behColl.Remove(existingBehavior);
                }

                else if ((bool)e.NewValue == true && existingBehavior == null)
                {
                    behColl.Add(new TBehavior());
                }    
            }
        }
    }

Vì vậy, bạn có thể đơn giản sử dụng lại nó với nhiều thành phần như sau:

public class ComboBoxBehaviour : AttachableForStyleBehavior<ComboBox, ComboBoxBehaviour>
    { ... }

Và trong XAML đủ để khai báo:

 <Style TargetType="ComboBox">
            <Setter Property="behaviours:ComboBoxBehaviour.IsEnabledForStyle" Value="True"/>

Vì vậy, về cơ bản, lớp AttachableForStyleBehavior đã tạo ra những thứ xaml, đăng ký thể hiện hành vi cho từng thành phần theo kiểu. Để biết thêm chi tiết, vui lòng xem liên kết.


Hoạt động như một sự quyến rũ! Với Scrollingbehavior của tôi kết hợp, tôi đã loại bỏ Inner RowDetailsTemplate-Datagrids không cuộn các Datagrids mẹ.
Philipp Michalski

Rất vui khi được giúp đỡ, tận hưởng =)
Roma Borodov

1
Còn về ràng buộc dữ liệu với các thuộc tính phụ thuộc trong Behavior thì sao?
JobaDiniz

Tôi không biết cách liên hệ với người dùng hoặc từ chối chỉnh sửa với phản hồi tiêu cực về cá nhân. Vì vậy, @Der_Meister thân mến và các biên tập viên khác, vui lòng đọc mã cẩn thận trước khi bạn cố gắng chỉnh sửa nó. Nó có thể ảnh hưởng đến những người dùng khác và danh tiếng của tôi nữa. Trong trường hợp này, bằng cách loại bỏ thuộc tính IsEnabledForStyle và kiên quyết thay thế nó bằng các phương thức tĩnh, bạn sẽ phá hủy khả năng liên kết với nó trong xaml, đó là điểm chính của câu hỏi này. Vì vậy, có vẻ như bạn đã không đọc mã cho đến cuối. Đáng buồn thay, tôi không thể từ chối chỉnh sửa của bạn với điểm trừ lớn, vì vậy hãy cẩn thận trong tương lai.
Roma Borodov

1
@RomaBorodov, mọi thứ đều hoạt động trong XAML. Đó là một cách chính xác để xác định thuộc tính đính kèm (khác với thuộc tính phụ thuộc). Xem tài liệu: docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/…
Der_Meister

19

1.Tạo thuộc tính đính kèm

public static class DataGridCellAttachedProperties
{
    //Register new attached property
    public static readonly DependencyProperty IsSingleClickEditModeProperty =
        DependencyProperty.RegisterAttached("IsSingleClickEditMode", typeof(bool), typeof(DataGridCellAttachedProperties), new UIPropertyMetadata(false, OnPropertyIsSingleClickEditModeChanged));

    private static void OnPropertyIsSingleClickEditModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var dataGridCell = d as DataGridCell;
        if (dataGridCell == null)
            return;

        var isSingleEditMode = GetIsSingleClickEditMode(d);
        var behaviors =  Interaction.GetBehaviors(d);
        var singleClickEditBehavior = behaviors.SingleOrDefault(x => x is SingleClickEditDataGridCellBehavior);

        if (singleClickEditBehavior != null && !isSingleEditMode)
            behaviors.Remove(singleClickEditBehavior);
        else if (singleClickEditBehavior == null && isSingleEditMode)
        {
            singleClickEditBehavior = new SingleClickEditDataGridCellBehavior();
            behaviors.Add(singleClickEditBehavior);
        }
    }

    public static bool GetIsSingleClickEditMode(DependencyObject obj)
    {
        return (bool) obj.GetValue(IsSingleClickEditModeProperty);
    }

    public static void SetIsSingleClickEditMode(DependencyObject obj, bool value)
    {
        obj.SetValue(IsSingleClickEditModeProperty, value);
    }
}

2.Tạo hành vi

public class SingleClickEditDataGridCellBehavior:Behavior<DataGridCell>
        {
            protected override void OnAttached()
            {
                base.OnAttached();
                AssociatedObject.PreviewMouseLeftButtonDown += DataGridCellPreviewMouseLeftButtonDown;
            }

            protected override void OnDetaching()
            {
                base.OnDetaching();
                AssociatedObject.PreviewMouseLeftButtonDown += DataGridCellPreviewMouseLeftButtonDown;
            }

            void DataGridCellPreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
            {
                 DataGridCell cell = sender as DataGridCell;
                if (cell != null && !cell.IsEditing && !cell.IsReadOnly)
                {
                    if (!cell.IsFocused)
                    {
                        cell.Focus();
                    }
                    DataGrid dataGrid = LogicalTreeWalker.FindParentOfType<DataGrid>(cell); //FindVisualParent<DataGrid>(cell);
                    if (dataGrid != null)
                    {
                        if (dataGrid.SelectionUnit != DataGridSelectionUnit.FullRow)
                        {
                            if (!cell.IsSelected)
                                cell.IsSelected = true;
                        }
                        else
                        {
                            DataGridRow row =  LogicalTreeWalker.FindParentOfType<DataGridRow>(cell); //FindVisualParent<DataGridRow>(cell);
                            if (row != null && !row.IsSelected)
                            {
                                row.IsSelected = true;
                            }
                        }
                    }
                }
            }    
        }

3.Tạo kiểu và đặt thuộc tính đính kèm

        <Style TargetType="{x:Type DataGridCell}">
            <Setter Property="Behaviors:DataGridCellAttachedProperties.IsSingleClickEditMode" Value="True"/>
        </Style>

Khi tôi cố gắng truy cập DependencyProperty từ kiểu nó cho biết IsSingleClickEditMode không được nhận dạng hoặc không thể truy cập được?
Igor Meszaros

Xin lỗi xấu của tôi .. ngay sau khi tôi nhận xét tôi nhận ra GetIsSingleClickEditMode nên phù hợp với chuỗi bạn vượt qua vào DependencyProperty.RegisterAttached
Igor Mészáros

OnDetaching thêm một trình xử lý sự kiện khác, điều này sẽ được sửa (không thể sửa đổi một ký tự khi chỉnh sửa bài đăng ...)
BalintPogatsa

11

Tôi có một ý tưởng khác, để tránh việc tạo thuộc tính đính kèm cho mọi hành vi:

  1. Giao diện người tạo hành vi:

    public interface IBehaviorCreator
    {
        Behavior Create();
    }
    
  2. Bộ sưu tập trợ giúp nhỏ:

    public class BehaviorCreatorCollection : Collection<IBehaviorCreator> { }
    
  3. Lớp trợ giúp gắn hành vi:

    public static class BehaviorInStyleAttacher
    {
        #region Attached Properties
    
        public static readonly DependencyProperty BehaviorsProperty =
            DependencyProperty.RegisterAttached(
                "Behaviors",
                typeof(BehaviorCreatorCollection),
                typeof(BehaviorInStyleAttacher),
                new UIPropertyMetadata(null, OnBehaviorsChanged));
    
        #endregion
    
        #region Getter and Setter of Attached Properties
    
        public static BehaviorCreatorCollection GetBehaviors(TreeView treeView)
        {
            return (BehaviorCreatorCollection)treeView.GetValue(BehaviorsProperty);
        }
    
        public static void SetBehaviors(
            TreeView treeView, BehaviorCreatorCollection value)
        {
            treeView.SetValue(BehaviorsProperty, value);
        }
    
        #endregion
    
        #region on property changed methods
    
        private static void OnBehaviorsChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue is BehaviorCreatorCollection == false)
                return;
    
            BehaviorCreatorCollection newBehaviorCollection = e.NewValue as BehaviorCreatorCollection;
    
            BehaviorCollection behaviorCollection = Interaction.GetBehaviors(depObj);
            behaviorCollection.Clear();
            foreach (IBehaviorCreator behavior in newBehaviorCollection)
            {
                behaviorCollection.Add(behavior.Create());
            }
        }
    
        #endregion
    }
    
  4. Bây giờ hành vi của bạn, triển khai IBehaviorCreator:

    public class SingleClickEditDataGridCellBehavior:Behavior<DataGridCell>, IBehaviorCreator
    {
        //some code ...
    
        public Behavior Create()
        {
            // here of course you can also set properties if required
            return new SingleClickEditDataGridCellBehavior();
        }
    }
    
  5. Và bây giờ sử dụng nó trong xaml:

    <Style TargetType="{x:Type DataGridCell}">
      <Setter Property="helper:BehaviorInStyleAttacher.Behaviors" >
        <Setter.Value>
          <helper:BehaviorCreatorCollection>
            <behaviors:SingleClickEditDataGridCellBehavior/>
          </helper:BehaviorCreatorCollection>
        </Setter.Value>
      </Setter>
    </Style>
    

5

Tôi không thể tìm thấy bài viết gốc nhưng tôi đã có thể tạo lại hiệu ứng.

#region Attached Properties Boilerplate

    public static readonly DependencyProperty IsActiveProperty = DependencyProperty.RegisterAttached("IsActive", typeof(bool), typeof(ScrollIntoViewBehavior), new PropertyMetadata(false, OnIsActiveChanged));

    public static bool GetIsActive(FrameworkElement control)
    {
        return (bool)control.GetValue(IsActiveProperty);
    }

    public static void SetIsActive(
      FrameworkElement control, bool value)
    {
        control.SetValue(IsActiveProperty, value);
    }

    private static void OnIsActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var behaviors = Interaction.GetBehaviors(d);
        var newValue = (bool)e.NewValue;

        if (newValue)
        {
            //add the behavior if we don't already have one
            if (!behaviors.OfType<ScrollIntoViewBehavior>().Any())
            {
                behaviors.Add(new ScrollIntoViewBehavior());
            }
        }
        else
        {
            //remove any instance of the behavior. (There should only be one, but just in case.)
            foreach (var item in behaviors.ToArray())
            {
                if (item is ScrollIntoViewBehavior)
                    behaviors.Remove(item);
            }
        }
    }


    #endregion
<Style TargetType="Button">
    <Setter Property="Blah:ScrollIntoViewBehavior.IsActive" Value="True" />
</Style>

Tuy nhiên, phải viết điều này cho mỗi hành vi là một chút PITA.
Stephen Drew

0

Mã hành vi mong đợi một Hình ảnh, vì vậy chúng tôi chỉ có thể thêm nó vào một Hình ảnh. Vì vậy, tùy chọn duy nhất tôi có thể thấy là thêm vào một trong những phần tử bên trong ControlTemplate để thêm hành vi vào Kiểu và ảnh hưởng đến tất cả các phiên bản của một điều khiển cụ thể.


0

Bài viết Giới thiệu về Hành vi đính kèm trong WPF thực hiện một hành vi đính kèm chỉ sử dụng Kiểu và cũng có thể liên quan hoặc hữu ích.

Kỹ thuật trong bài viết "Giới thiệu về các Hành vi được đính kèm" tránh hoàn toàn các thẻ Tương tác, sử dụng trên Kiểu. Tôi không biết liệu điều này có phải chỉ vì nó là một kỹ thuật cũ hơn, hay nếu điều đó vẫn mang lại một số lợi ích mà người ta nên thích nó hơn trong một số trường hợp.


2
Đây không phải là một hành vi Blend, nó là một "hành vi" thông qua một thuộc tính đơn giản được đính kèm.
Stephen Drew

0

Tôi thích cách tiếp cận được chỉ ra bởi câu trả lời của Roman Dvoskin và Jonathan Allen trong chủ đề này. Tuy nhiên, khi lần đầu tiên tôi học kỹ thuật đó, tôi đã được hưởng lợi từ bài đăng trên blog này cung cấp nhiều giải thích hơn về kỹ thuật này. Và để xem mọi thứ trong ngữ cảnh, đây là toàn bộ mã nguồn của lớp mà tác giả nói đến trong bài đăng trên blog của mình.


0

Khai báo hành vi / trình kích hoạt cá nhân dưới dạng Tài nguyên:

<Window.Resources>

    <i:EventTrigger x:Key="ET1" EventName="Click">
        <ei:ChangePropertyAction PropertyName="Background">
            <ei:ChangePropertyAction.Value>
                <SolidColorBrush Color="#FFDAD32D"/>
            </ei:ChangePropertyAction.Value>
        </ei:ChangePropertyAction>
    </i:EventTrigger>

</Window.Resources>

Chèn chúng vào bộ sưu tập:

<Button x:Name="Btn1" Content="Button">

        <i:Interaction.Triggers>
             <StaticResourceExtension ResourceKey="ET1"/>
        </i:Interaction.Triggers>

</Button>

4
Nó trả lời OP như thế nào? Trình kích hoạt không được thêm thông qua một kiểu trong câu trả lời của bạn.
Kryptos

0

Dựa trên câu trả lời này, tôi đã đưa ra một giải pháp đơn giản hơn, chỉ cần một lớp và không cần phải triển khai thứ gì khác trong các hành vi của bạn.

public static class BehaviorInStyleAttacher
{
    #region Attached Properties

    public static readonly DependencyProperty BehaviorsProperty =
        DependencyProperty.RegisterAttached(
            "Behaviors",
            typeof(IEnumerable),
            typeof(BehaviorInStyleAttacher),
            new UIPropertyMetadata(null, OnBehaviorsChanged));

    #endregion

    #region Getter and Setter of Attached Properties

    public static IEnumerable GetBehaviors(DependencyObject dependencyObject)
    {
        return (IEnumerable)dependencyObject.GetValue(BehaviorsProperty);
    }

    public static void SetBehaviors(
        DependencyObject dependencyObject, IEnumerable value)
    {
        dependencyObject.SetValue(BehaviorsProperty, value);
    }

    #endregion

    #region on property changed methods

    private static void OnBehaviorsChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
    {
        if (e.NewValue is IEnumerable == false)
            return;

        var newBehaviorCollection = e.NewValue as IEnumerable;

        BehaviorCollection behaviorCollection = Interaction.GetBehaviors(depObj);
        behaviorCollection.Clear();
        foreach (Behavior behavior in newBehaviorCollection)
        {
            // you need to make a copy of behavior in order to attach it to several controls
            var copy = behavior.Clone() as Behavior;
            behaviorCollection.Add(copy);
        }
    }

    #endregion
}

và cách sử dụng mẫu là

<Style TargetType="telerik:RadComboBox" x:Key="MultiPeriodSelectableRadComboBox">
    <Setter Property="AllowMultipleSelection" Value="True" />
    <Setter Property="behaviors:BehaviorInStyleAttacher.Behaviors">
        <Setter.Value>
            <collections:ArrayList>
                <behaviors:MultiSelectRadComboBoxBehavior
                        SelectedItems="{Binding SelectedPeriods}"
                        DelayUpdateUntilDropDownClosed="True"
                        SortSelection="True" 
                        ReverseSort="True" />
            </collections:ArrayList>
        </Setter.Value>
    </Setter>
</Style>

Đừng quên thêm xmlns này để sử dụng ArrayList:

xmlns:collections="clr-namespace:System.Collections;assembly=mscorlib"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.