Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/263.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_Xaml_Expression Blend - Fatal编程技术网

C# 如何在样式设置器中添加混合行为

C# 如何在样式设置器中添加混合行为,c#,wpf,xaml,expression-blend,C#,Wpf,Xaml,Expression Blend,我为巴顿设计了一个混合行为。如何将其设置为应用程序中的所有按钮 <Button ...> <i:Interaction.Behaviors> <local:MyBehavior /> </i:Interaction.Behaviors> </Button> 但是,当我尝试时: <Style> <Setter Property="i:Interaction.Behaviors">

我为巴顿设计了一个混合行为。如何将其设置为应用程序中的所有按钮

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

但是,当我尝试时:

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

我得到了错误

属性“行为”没有可访问的setter


行为代码需要一个视觉效果,所以我们只能在视觉效果上添加它。因此,我能看到的唯一选项是添加到ControlTemplate中的一个元素,以便将行为添加到样式中,并影响特定控件的所有实例。

我也遇到了同样的问题,我找到了解决方案。我在解决这个问题后发现了这个问题,我发现我的解决方案与马克的有很多共同之处。然而,这种方法有点不同

主要问题是行为和触发器与特定对象关联,因此不能对多个不同的关联对象使用相同的行为实例。定义行为时,内联XAML将强制执行这种一对一关系。但是,当您尝试在样式中设置行为时,该样式可以重新用于它应用于的所有对象,这将在基本行为类中引发异常。事实上,作者花了相当大的努力来阻止我们尝试这样做,因为他们知道这样做行不通

第一个问题是,我们甚至无法构造行为设置器值,因为构造函数是内部的。所以我们需要自己的行为和触发器集合类

下一个问题是行为和触发器附加的属性没有setter,因此只能使用内嵌XAML将它们添加到。我们使用自己附加的属性来解决这个问题,这些属性操纵主要行为和触发器属性

第三个问题是,我们的行为集合只适用于单一样式的目标。我们通过利用很少使用的XAML特性
x:Shared=“False”
来解决这个问题,该特性在每次引用资源时都会创建一个新的资源副本

最后一个问题是,行为和触发器与其他样式设置器不同;我们不想用新的行为取代旧的行为,因为它们可以做完全不同的事情。因此,如果我们接受一旦你添加了一个行为,你就不能把它拿走(这就是当前行为的工作方式),我们可以得出结论,行为和触发器应该是可添加的,这可以通过我们附加的属性来处理

以下是使用此方法的示例:

<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>
最后,我们的收藏和附加属性使这一切工作。与
Interaction.Behaviors
类似,您的目标属性称为
SupplementaryInteraction.Behaviors
,因为通过设置此属性,您将向
Interaction.Behaviors
添加行为,同样地,也会向触发器添加行为

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);
    }
}
公共类行为:列表
{
}
公共类触发器:列表
{
}
公共静态课堂补充互动
{
公共静态行为GetBehaviors(DependencyObject obj)
{
返回(行为)对象获取值(行为属性);
}
公共静态无效设置行为(DependencyObject对象、行为值)
{
对象设置值(行为属性,值);
}
公共静态只读DependencyProperty BehaviorsProperty=
DependencyProperty.RegisterAttached(“行为”、类型(行为)、类型(补充交互)、新UIPropertyMetadata(null、OnPropertyBehaviorChanged));
私有静态无效OnPropertyBehaviorsChanged(DependencyObject d,DependencyPropertyChangedEventArgs e)
{
var行为=交互。GetBehaviors(d);
foreach(e.NewValue中的var行为作为行为)Behaviors.Add(行为);
}
公共静态触发器GetTriggers(DependencyObject obj)
{
返回(触发器)对象获取值(触发器属性);
}
公共静态void SetTriggers(DependencyObject对象,触发器值)
{
对象设置值(触发器属性,值);
}
公共静态只读从属属性触发器属性=
DependencyProperty.RegisterAttached(“触发器”、typeof(触发器)、typeof(补充交互)、新UIPropertyMetadata(null、OnPropertyTriggersChanged));
私有静态无效OnPropertyTriggersChanged(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
var触发器=Interaction.GetTriggers(d);
foreach(e.NewValue中的var触发器作为触发器)Triggers.Add(触发器);
}
}

在这里,通过样式应用了功能齐全的行为和触发器。

我找不到原始文章,但我能够重新创建效果

#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
#区域附加属性样板
public static readonly dependencProperty isActivityProperty=dependencProperty.RegisterAttached(“IsActive”、typeof(bool)、typeof(ScrollIntoViewBehavior)、new PropertyMetadata(false、OnIsActiveChanged));
公共静态bool GetIsActive(FrameworkElement控件)
{
return(bool)control.GetValue(isActivityProperty);
}
公共静态无效设置活动(
FrameworkElement控件,布尔值)
{
control.SetValue(IsActivityProperty,value);
}
私有静态无效OnIsActiveChanged(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
var行为=交互。GetBehaviors(d);
var newValue=(bool)e.newValue;
如果(新值)
{
//如果我们还没有行为,请添加行为
如果(!behaviors.OfType().Any())
{
添加(新的ScrollIntoViewBehavior());
}
}
其他的
{
//删除该行为的任何实例。(应该只有一个,但以防万一。)
foreach(behaviors.ToArray()中的变量项)
{
如果(项目为ScrollIntoViewBehavior)
行为。删除(项目);
}
}
}
#端区

#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>
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);
    }
}
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;
                            }
                        }
                    }
                }
            }    
        }
        <Style TargetType="{x:Type DataGridCell}">
            <Setter Property="Behaviors:DataGridCellAttachedProperties.IsSingleClickEditMode" Value="True"/>
        </Style>
public interface IBehaviorCreator
{
    Behavior Create();
}
public class BehaviorCreatorCollection : Collection<IBehaviorCreator> { }
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
}
public class SingleClickEditDataGridCellBehavior:Behavior<DataGridCell>, IBehaviorCreator
{
    //some code ...

    public Behavior Create()
    {
        // here of course you can also set properties if required
        return new SingleClickEditDataGridCellBehavior();
    }
}
<Style TargetType="{x:Type DataGridCell}">
  <Setter Property="helper:BehaviorInStyleAttacher.Behaviors" >
    <Setter.Value>
      <helper:BehaviorCreatorCollection>
        <behaviors:SingleClickEditDataGridCellBehavior/>
      </helper:BehaviorCreatorCollection>
    </Setter.Value>
  </Setter>
</Style>
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());
                }    
            }
        }
    }
public class ComboBoxBehaviour : AttachableForStyleBehavior<ComboBox, ComboBoxBehaviour>
    { ... }
 <Style TargetType="ComboBox">
            <Setter Property="behaviours:ComboBoxBehaviour.IsEnabledForStyle" Value="True"/>
<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>
<Button x:Name="Btn1" Content="Button">

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

</Button>
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
}
<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>
xmlns:collections="clr-namespace:System.Collections;assembly=mscorlib"