Bagaimana cara menambahkan Blend Behavior dalam Style Setter

88

Saya telah menyusun perilaku Blend untuk Button. Bagaimana cara mengaturnya ke semua Tombol saya di aplikasi.

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

Namun, ketika saya mencoba:

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

Saya mendapatkan kesalahan

Properti "Perilaku" tidak memiliki penyetel yang dapat diakses.

Joy Jobi
sumber

Jawaban:

76

Saya memiliki masalah yang sama dan saya telah menemukan solusinya. Saya menemukan pertanyaan ini setelah saya menyelesaikannya dan saya melihat bahwa solusi saya memiliki banyak kesamaan dengan Mark. Namun, pendekatan ini sedikit berbeda.

Masalah utamanya adalah bahwa perilaku dan pemicu terkait dengan objek tertentu, sehingga Anda tidak dapat menggunakan contoh perilaku yang sama untuk beberapa objek terkait yang berbeda. Ketika Anda mendefinisikan perilaku Anda sebaris XAML memberlakukan hubungan satu-ke-satu ini. Namun, saat Anda mencoba menyetel perilaku dalam sebuah gaya, gaya tersebut dapat digunakan kembali untuk semua objek yang diterapkan padanya dan ini akan memunculkan pengecualian di kelas perilaku dasar. Sebenarnya para penulis berusaha keras untuk mencegah kami mencoba melakukan ini, mengetahui bahwa itu tidak akan berhasil.

Masalah pertama adalah bahwa kita bahkan tidak dapat membuat nilai penyetel perilaku karena konstruktornya internal. Jadi kita membutuhkan perilaku kita sendiri dan memicu kelas pengumpulan.

Masalah berikutnya adalah bahwa perilaku dan pemicu properti terlampir tidak memiliki penyetel sehingga mereka hanya dapat ditambahkan ke dengan XAML sebaris. Masalah ini kami selesaikan dengan properti terlampir kami sendiri yang memanipulasi perilaku utama dan properti pemicu.

Masalah ketiga adalah bahwa koleksi perilaku kita hanya bagus untuk satu target gaya. Ini kami selesaikan dengan memanfaatkan fitur XAML yang jarang digunakan x:Shared="False"yang membuat salinan baru dari sumber daya setiap kali direferensikan.

Masalah terakhir adalah bahwa perilaku dan pemicu tidak seperti penentu gaya lainnya; kami tidak ingin mengganti perilaku lama dengan perilaku baru karena mereka dapat melakukan hal yang sangat berbeda. Jadi, jika kami menerima bahwa setelah Anda menambahkan perilaku, Anda tidak dapat menghilangkannya (dan begitulah cara perilaku saat ini), kami dapat menyimpulkan bahwa perilaku dan pemicu harus bersifat aditif dan ini dapat ditangani oleh properti terlampir kami.

Berikut adalah contoh yang menggunakan pendekatan ini:

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

Contoh tersebut menggunakan pemicu tetapi perilaku bekerja dengan cara yang sama. Dalam contoh, kami menunjukkan:

  • gaya dapat diterapkan ke beberapa blok teks
  • beberapa jenis data binding semuanya bekerja dengan benar
  • tindakan debug yang menghasilkan teks di jendela keluaran

Berikut adalah contoh perilaku kami DebugAction. Lebih tepatnya ini adalah suatu tindakan tetapi melalui penyalahgunaan bahasa kita menyebut perilaku, pemicu, dan tindakan "perilaku".

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);
    }
}

Akhirnya, koleksi kami dan properti terlampir membuat ini semua berfungsi. Dengan analogi Interaction.Behaviors, properti yang Anda targetkan dipanggil SupplementaryInteraction.Behaviorskarena dengan menyetel properti ini, Anda akan menambahkan perilaku Interaction.Behaviorsdan begitu juga untuk pemicu.

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);
    }
}

dan begitulah, perilaku dan pemicu yang berfungsi penuh diterapkan melalui gaya.

Rick Sladkey
sumber
Bagus, ini bekerja dengan indah. Saya perhatikan bahwa jika Anda meletakkan gaya, misalnya, di sumber daya UserControl, maka e.NewValue mungkin nol pada awalnya (mungkin bergantung pada kontrol yang digunakan - Saya menggunakan ini pada XamDataTreeNodeControl di Infragistics XamDataTree). Jadi saya menambahkan sedikit pemeriksaan kewarasan di OnPropertyTriggersChanged: if (e.NewValue! = Null)
MetalMikester
Adakah yang punya masalah dengan pendekatan ini saat menerapkan Setter dalam Style implisit ? Saya membuatnya berfungsi dengan baik dengan gaya non-implisit (satu dengan Key), tetapi saya mendapatkan pengecualian referensi siklik jika dalam gaya implisit.
Jason Frank
1
Solusi bagus, tetapi sayangnya tidak berfungsi di WinRT, karena x: Dibagikan tidak ada di platform ini ...
Thomas Levesque
1
Saya dapat mengonfirmasi bahwa solusi ini berfungsi. Terima kasih banyak telah membagikannya. Saya belum mencobanya dengan gaya implisit.
Golvellius
2
@ Jason Frank, Terima kasih, Sama seperti referensi untuk orang lain ... Saya membuatnya berfungsi dalam kedua kasus: Implisit dan eksplisit. Sebenarnya saya mengajukan pertanyaan di mana saya akan meletakkan semua kode saya untuk membantu orang lain tetapi seseorang memperkirakan bahwa pertanyaan saya adalah duplikat. Saya tidak dapat menjawab pertanyaan saya sendiri dengan memberikan semua yang saya temukan. Saya rasa saya menemukan hal-hal yang cukup bagus. :-( ... Saya harap ini tidak terjadi terlalu sering karena perilaku tersebut membuat pengguna lain kehilangan informasi yang berguna.
Eric Ouellet
27

Menjumlahkan jawaban dan artikel hebat ini Memadukan Perilaku dalam Gaya , saya sampai pada solusi umum yang singkat dan mudah ini:

Saya membuat kelas generik, yang dapat diwariskan oleh perilaku apa pun.

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());
                }    
            }
        }
    }

Jadi Anda bisa menggunakannya kembali dengan banyak komponen seperti ini:

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

Dan di XAML cukup untuk menyatakan:

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

Jadi pada dasarnya kelas AttachableForStyleBehavior membuat xaml things, mendaftarkan contoh perilaku untuk setiap komponen dalam gaya. Untuk lebih jelasnya, silakan lihat tautannya.

Roma Borodov
sumber
Bekerja seperti pesona! Dengan gabungan perilaku Scrolling, saya menyingkirkan Inner RowDetailsTemplate-Datagrids yang tidak menggulir induk Datagrids.
Philipp Michalski
Senang membantu, nikmati =)
Roma Borodov
1
bagaimana dengan data binding dengan properti dependensi di Behavior?
JobaDiniz
Saya tidak tahu cara menghubungi pengguna atau menolak mengedit dengan umpan balik negatif secara pribadi. Jadi @Der_Meister dan editor lainnya, harap baca kode dengan cermat sebelum Anda mencoba mengeditnya. Ini dapat memengaruhi pengguna lain dan reputasi saya juga. Dalam kasus ini, dengan menghapus properti IsEnabledForStyle dan terus-menerus menggantinya dengan metode statis, Anda menghancurkan kemungkinan mengikatnya di xaml, yang merupakan poin utama dari pertanyaan ini. Jadi sepertinya Anda tidak membaca kode sampai akhir. Sayangnya saya tidak bisa menolak suntingan Anda dengan minus besar, jadi harap berhati-hati di masa depan.
Roma Borodov
1
@RomaBorodov, semuanya bekerja di XAML. Ini adalah cara yang benar untuk mendefinisikan properti terlampir (yang berbeda dari properti ketergantungan). Lihat dokumentasi: docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/…
Der_Meister
19

1. Buat Properti Terlampir

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. Ciptakan Perilaku

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. Buat Style dan setel properti terlampir

        <Style TargetType="{x:Type DataGridCell}">
            <Setter Property="Behaviors:DataGridCellAttachedProperties.IsSingleClickEditMode" Value="True"/>
        </Style>
Roman Dvoskin
sumber
Ketika saya mencoba mengakses DependencyProperty dari gayanya, dikatakan IsSingleClickEditMode tidak dikenali atau tidak dapat diakses?
Igor Meszaros
Maaf saya buruk .. segera setelah saya berkomentar saya menyadari GetIsSingleClickEditMode harus cocok dengan string yang Anda berikan ke DependencyProperty.RegisterAttached
Igor Meszaros
OnDetaching menambahkan penangan peristiwa lain, ini harus diperbaiki (tidak dapat mengubah satu karakter saat mengedit posting ...)
BalintPogatsa
11

Saya punya ide lain, untuk menghindari pembuatan properti terlampir untuk setiap perilaku:

  1. Antarmuka pencipta perilaku:

    public interface IBehaviorCreator
    {
        Behavior Create();
    }
    
  2. Koleksi pembantu kecil:

    public class BehaviorCreatorCollection : Collection<IBehaviorCreator> { }
    
  3. Kelas pembantu yang melampirkan perilaku:

    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. Sekarang perilaku Anda, yang mengimplementasikan 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. Dan sekarang gunakan di xaml:

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

Saya tidak dapat menemukan artikel aslinya tetapi saya dapat membuat ulang efeknya.

#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>
Jonathan Allen
sumber
Harus menulis ini untuk setiap perilaku adalah sedikit PITA.
Stephen Drew
0

Kode perilaku mengharapkan Visual, jadi kita bisa menambahkannya hanya pada visual. Jadi satu-satunya pilihan yang bisa saya lihat adalah menambahkan salah satu elemen di dalam ControlTemplate agar perilaku ditambahkan ke Style dan memengaruhi semua instance dari kontrol tertentu.

Joy Jobi
sumber
0

Artikel Pengenalan Perilaku Terlampir di WPF mengimplementasikan perilaku terlampir hanya menggunakan Gaya, dan mungkin juga terkait atau membantu.

Teknik dalam artikel "Pengantar Perilaku Terlampir" menghindari tag Interaktivitas sama sekali, menggunakan pada Style. Saya tidak tahu apakah ini hanya karena ini adalah teknik yang lebih kuno, atau, jika itu masih memberikan beberapa manfaat di mana seseorang harus lebih memilihnya dalam beberapa skenario.

Tagihan
sumber
2
Ini bukan perilaku Blend, ini adalah "perilaku" melalui properti terlampir sederhana.
Stephen Drew
0

Saya suka pendekatan yang ditunjukkan oleh jawaban Roman Dvoskin dan Jonathan Allen di utas ini. Ketika saya pertama kali mempelajari teknik itu, saya mendapat manfaat dari posting blog ini yang memberikan lebih banyak penjelasan tentang teknik itu. Dan untuk melihat semuanya dalam konteks, berikut adalah seluruh kode sumber untuk kelas yang dibicarakan oleh penulis dalam posting blognya.

Jason Frank
sumber
0

Nyatakan perilaku / pemicu individu sebagai Sumber:

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

Masukkan mereka ke dalam koleksi:

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

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

</Button>
AnjumSKhan
sumber
4
Bagaimana cara menjawab OP? Pemicu tidak ditambahkan melalui gaya dalam jawaban Anda.
Kryptos
0

Berdasarkan jawaban ini saya membuat solusi yang lebih sederhana, dengan hanya satu kelas yang dibutuhkan dan tidak perlu menerapkan sesuatu yang lain dalam perilaku Anda.

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
}

dan penggunaan sampelnya adalah

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

Jangan lupa untuk menambahkan xmlns ini untuk menggunakan ArrayList:

xmlns:collections="clr-namespace:System.Collections;assembly=mscorlib"
technopriest
sumber