Interaction Triggers in Style in ResourceDictionary WPF

后端 未结 2 1968
面向向阳花
面向向阳花 2020-12-03 00:02

I have a ComboBox which I need to use in several places in my application, so I set most of the properties of that ComboBox in ResourceDictio

相关标签:
2条回答
  • 2020-12-03 00:49

    As far as I know, Interaction.Triggers can not be applied in Style, respectively and in a ResourceDictionary. But you can do so, to determine the ComboBox as a resource with x:Shared="False" and reference it for ContentControl like this:

    <Window.Resources>
        <ComboBox x:Key="MyComboBox"
                  x:Shared="False"
                  ItemsSource="{Binding Branches}"
                  DisplayMemberPath="BranchName"
                  SelectedItem="{Binding SelectedBranch}">
    
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="SelectionChanged">
                    <i:InvokeCommandAction Command="{Binding SelectCustomerCommand}" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </ComboBox>
    </Window.Resources>
    
    <Grid>
        <ContentControl Name="MyComboBox1"
                        Width="100"
                        Height="30"
                        HorizontalAlignment="Left"
                        Content="{StaticResource MyComboBox}" />
    
        <ContentControl Name="MyComboBox2"
                        Width="100"
                        Height="30"
                        HorizontalAlignment="Right"
                        Content="{StaticResource MyComboBox}" />
    </Grid>
    

    When x:Shared="True" by default then one Style is common to all - in this case, the system swears on the duplicate Content. When x:Shared="False" when is created Style for each element whenever it its request. Quote from MSDN:

    When set to false, modifies WPF resource-retrieval behavior so that requests for the attributed resource create a new instance for each request instead of sharing the same instance for all requests.

    For more information, please see:

    MSDN: x:Shared Attribute

    Edit: alternative solution

    Here, Mr.Vspivak published a solution that allows you easily set the Interaction.Triggers in Style.

    Example:

    MainWindow.xaml

    <Window x:Class="StylesInteractivity.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
            xmlns:ie="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
            xmlns:Core="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions" 
            xmlns:int="clr-namespace:System.Windows.Interactivity" 
            xmlns:si="clr-namespace:StylesInteractivity"
            Title="MainWindow" Height="350" Width="525">
    
        <Window.Resources>
            <si:ViewModel x:Key="Model" />
        </Window.Resources>
    
        <Grid>      
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
    
            <TextBlock Grid.Column="1" x:Name="_tblock" 
                       Text="Default" 
                       HorizontalAlignment="Center" 
                       VerticalAlignment="Center" 
                       FontSize="24" 
                       FontWeight="Bold" />
    
            <ListBox ItemsSource="{Binding Source={StaticResource Model}, Path=DataSource}" 
                     Grid.Column="0"
                     HorizontalAlignment="Center" 
                     VerticalAlignment="Center">
    
                <ListBox.ItemContainerStyle>
                    <Style TargetType="ListBoxItem">
                        <Setter Property="FontSize" Value="24"/>
                        <Setter Property="FontWeight" Value="Bold"/>
    
                        <Setter Property="int:InteractivityItems.Template">
                            <Setter.Value>
                                <int:InteractivityTemplate>
                                    <int:InteractivityItems>
                                        <int:InteractivityItems.Behaviors>
                                            <int:FlipOnHover />
                                        </int:InteractivityItems.Behaviors>
    
                                        <int:InteractivityItems.Triggers>
                                            <ie:EventTrigger EventName="MouseMove">
                                                <Core:ChangePropertyAction PropertyName="Text"
                                                                           TargetObject="{Binding ElementName=_tblock}"
                                                                           Value="{Binding}" />
                                            </ie:EventTrigger>
                                        </int:InteractivityItems.Triggers>
                                    </int:InteractivityItems>
                                </int:InteractivityTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </ListBox.ItemContainerStyle>
            </ListBox>
        </Grid>
    </Window>
    

    InteractivityHelper.cs

    /// <summary>
    /// <see cref="FrameworkTemplate"/> for InteractivityElements instance
    /// <remarks>Subclassed for forward compatibility, perhaps one day <see cref="FrameworkTemplate"/> </remarks>
    /// <remarks>will not be partially internal</remarks>
    /// </summary>
    public class InteractivityTemplate : DataTemplate
    {
    
    }
    
    /// <summary>
    /// Holder for interactivity entries
    /// </summary>
    public class InteractivityItems : FrameworkElement
    {
        private List<Behavior> _behaviors;
        private List<TriggerBase> _triggers;
    
        /// <summary>
        /// Storage for triggers
        /// </summary>
        public List<TriggerBase> Triggers
        {
            get
            {
                if (_triggers == null)
                    _triggers = new List<TriggerBase>();
                return _triggers;
            }
        }
    
        /// <summary>
        /// Storage for Behaviors
        /// </summary>
        public List<Behavior> Behaviors
        {
            get
            {
                if (_behaviors == null)
                    _behaviors = new List<Behavior>();
                return _behaviors;
            }
        }
    
        #region Template attached property
    
        public static InteractivityTemplate GetTemplate(DependencyObject obj)
        {
            return (InteractivityTemplate)obj.GetValue(TemplateProperty);
        }
    
        public static void SetTemplate(DependencyObject obj, InteractivityTemplate value)
        {
            obj.SetValue(TemplateProperty, value);
        }
    
        public static readonly DependencyProperty TemplateProperty =
            DependencyProperty.RegisterAttached("Template", 
            typeof(InteractivityTemplate), 
            typeof(InteractivityItems),
            new PropertyMetadata(default(InteractivityTemplate), OnTemplateChanged));
    
        private static void OnTemplateChanged(
            DependencyObject d, 
            DependencyPropertyChangedEventArgs e)
        {
            InteractivityTemplate dt = (InteractivityTemplate)e.NewValue;
    #if(!SILVERLIGHT)
            dt.Seal();
    #endif
            InteractivityItems ih = (InteractivityItems)dt.LoadContent();
            BehaviorCollection bc = Interaction.GetBehaviors(d);
            TriggerCollection tc = Interaction.GetTriggers(d);
    
            foreach (Behavior behavior in ih.Behaviors)
                bc.Add(behavior);
    
            foreach (TriggerBase trigger in ih.Triggers)
                tc.Add(trigger);
        }
    
        #endregion
    }
    

    FlipOnHover.cs

    public class FlipOnHover : Behavior<FrameworkElement>
    {
        protected override void OnAttached()
        {
            AssociatedObject.MouseEnter += AssociatedObject_MouseEnter;
            AssociatedObject.MouseLeave += AssociatedObject_MouseLeave;
            Transform t = AssociatedObject.RenderTransform;
    
            AssociatedObject.RenderTransform = new TransformGroup();
            ((TransformGroup)AssociatedObject.RenderTransform).Children.Add(t);
            ((TransformGroup)AssociatedObject.RenderTransform).Children.Add(new ScaleTransform());
            base.OnAttached();
        }
    
        void AssociatedObject_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
        {
            ((ScaleTransform)((TransformGroup)AssociatedObject.RenderTransform).Children[1]).ScaleY = 1;
        }
    
        void AssociatedObject_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
        {
            ((ScaleTransform)((TransformGroup)AssociatedObject.RenderTransform).Children[1]).CenterX = AssociatedObject.ActualWidth / 2;
            ((ScaleTransform)((TransformGroup)AssociatedObject.RenderTransform).Children[1]).CenterY = AssociatedObject.ActualHeight / 2;
            ((ScaleTransform)((TransformGroup)AssociatedObject.RenderTransform).Children[1]).ScaleY=-1;
        }
    
        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.MouseEnter -= AssociatedObject_MouseEnter;
            AssociatedObject.MouseLeave -= AssociatedObject_MouseLeave;
        }
    }
    

    ViewModel.cs

    public class ViewModel
    {
        private ObservableCollection<String> _dataSource = new ObservableCollection<string>();
    
        public ViewModel()
        {
            _dataSource.Add("Cat");
            _dataSource.Add("Dog");
            _dataSource.Add("Mouse");
            _dataSource.Add("Owl");
            _dataSource.Add("Rabbit");
        }
    
        public IEnumerable<string> DataSource
        {
            get { return _dataSource; }
        }
    }
    

    For more info, see this link:

    Using Interactivity Behaviors and Actions in WPF/Silverlight Styles

    0 讨论(0)
  • 2020-12-03 00:52

    I usually work with Silverlight so I'm not sure if the following approach is sensible in WPF: You can pull your xaml into a UserControl, say BranchSelection.xaml for example:

    <UserControl x:Class="foobar.BranchSelection">
        <ComboBox 
            ItemsSource="{Binding Branches}"
            DisplayMemberPath="BranchName"
            SelectedItem="{Binding SelectedBranch}">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="SelectionChanged">
                    <i:InvokeCommandAction
                        Command="{Binding SelectCustomerCommand}"
                        CommandParameter="{Binding SelectedBranch}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </ComboBox>
    </UserControl>
    

    And use it like this:

    <StackPanel>
        <BranchSelection x:Name="CustomerSelector_1"/>
        <BranchSelection x:Name="CustomerSelector_2"/>
    </StackPanel>
    
    0 讨论(0)
提交回复
热议问题