none
wpf 在.net4.5下RichTextBox的Style内控件不能添加事件 RRS feed

  • 问题

  • 这是.net4.5下生成的RichTextBox的Style副本
    <Style x:Key="RichTextBoxStyle1" TargetType="{x:Type RichTextBox}">
                <Style.Resources>
                    <Style x:Key="{x:Type FlowDocument}" TargetType="{x:Type FlowDocument}">
                        <Setter Property="OverridesDefaultStyle" Value="True"/>
                    </Style>
                    <Style x:Key="{x:Type Hyperlink}" TargetType="{x:Type Hyperlink}">
                        <Style.BasedOn>
                            <Style TargetType="{x:Type Hyperlink}">
                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HotTrackBrushKey}}"/>
                                <Setter Property="TextDecorations" Value="Underline"/>
                                <Style.Triggers>
                                    <Trigger Property="IsMouseOver" Value="True">
                                        <Setter Property="Foreground" Value="Red"/>
                                    </Trigger>
                                    <Trigger Property="IsEnabled" Value="False">
                                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                                    </Trigger>
                                    <Trigger Property="IsEnabled" Value="True">
                                        <Setter Property="Cursor" Value="Hand"/>
                                    </Trigger>
                                </Style.Triggers>
                            </Style>
                        </Style.BasedOn>
                        <Style.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Foreground" Value="Blue"/>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="False">
                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </Style.Resources>
                <Setter Property="MinWidth" Value="10"/>
                <Style.BasedOn>
                    <Style TargetType="{x:Type TextBoxBase}">
                        <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
                        <Setter Property="BorderBrush" Value="#FFABADB3"/>
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
                        <Setter Property="BorderThickness" Value="1"/>
                        <Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
                        <Setter Property="HorizontalContentAlignment" Value="Left"/>
                        <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
                        <Setter Property="AllowDrop" Value="True"/>
                        <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
                        <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="{x:Type TextBoxBase}">
                                    <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                                        <ScrollViewer x:Name="PART_ContentHost" Focusable="False" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"
                                                      Loaded="PART_ContentHost_OnLoaded"/>
                                    </Border>
                                    <ControlTemplate.Triggers>
                                        <Trigger Property="IsEnabled" Value="False">
                                            <Setter Property="Opacity" TargetName="border" Value="0.56"/>
                                        </Trigger>
                                        <Trigger Property="IsMouseOver" Value="True">
                                            <Setter Property="BorderBrush" TargetName="border" Value="#FF7EB4EA"/>
                                        </Trigger>
                                        <Trigger Property="IsKeyboardFocused" Value="True">
                                            <Setter Property="BorderBrush" TargetName="border" Value="#FF569DE5"/>
                                        </Trigger>
                                    </ControlTemplate.Triggers>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                        <Style.Triggers>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="IsInactiveSelectionHighlightEnabled" Value="True"/>
                                    <Condition Property="IsSelectionActive" Value="False"/>
                                </MultiTrigger.Conditions>
                                <Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
                            </MultiTrigger>
                        </Style.Triggers>
                    </Style>
                </Style.BasedOn>
            </Style>
    我给PART_ContentHost添加事件编译后提示error MC4007: 无法在 Style 中的 Target 标记上指定事件“Loaded”。请使用 EventSetter。
    而在.net4.0下的Style是
    <LinearGradientBrush x:Key="TextBoxBorder" EndPoint="0,20" MappingMode="Absolute" StartPoint="0,0">
                <GradientStop Color="#ABADB3" Offset="0.05"/>
                <GradientStop Color="#E2E3EA" Offset="0.07"/>
                <GradientStop Color="#E3E9EF" Offset="1"/>
            </LinearGradientBrush>
            <Style x:Key="{x:Type TextBoxBase}" BasedOn="{x:Null}" TargetType="{x:Type TextBoxBase}">
                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
                <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
                <Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}"/>
                <Setter Property="BorderThickness" Value="1"/>
                <Setter Property="Padding" Value="1"/>
                <Setter Property="AllowDrop" Value="true"/>
                <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type TextBoxBase}">
                            <Themes:ListBoxChrome x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" SnapsToDevicePixels="true">
                                <ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                            </Themes:ListBoxChrome>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsEnabled" Value="false">
                                    <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
                                    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
            <Style x:Key="{x:Type Hyperlink}" TargetType="{x:Type Hyperlink}">
                <Setter Property="Foreground" Value="Blue"/>
                <Setter Property="TextDecorations" Value="Underline"/>
                <Style.Triggers>
                    <Trigger Property="IsMouseOver" Value="true">
                        <Setter Property="Foreground" Value="Red"/>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="true">
                        <Setter Property="Cursor" Value="Hand"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
            <Style x:Key="RichTextBoxStyle1" TargetType="{x:Type RichTextBox}">
                <Style.Resources>
                    <Style x:Key="{x:Type FlowDocument}" TargetType="{x:Type FlowDocument}">
                        <Setter Property="OverridesDefaultStyle" Value="true"/>
                    </Style>
                    <Style x:Key="{x:Type Hyperlink}" BasedOn="{StaticResource {x:Type Hyperlink}}" TargetType="{x:Type Hyperlink}">
                        <Style.Triggers>
                            <Trigger Property="IsMouseOver" Value="true">
                                <Setter Property="Foreground" Value="Blue"/>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </Style.Resources>
                <Setter Property="MinWidth" Value="10"/>
                <Style.BasedOn>
                    <StaticResource ResourceKey="{x:Type TextBoxBase}"/>
                </Style.BasedOn>
            </Style>
    我同样给PART_ContentHost添加了Loaded事件,编译没有问题。

    请教一下,如果是.net4.5框架的话 怎么给PART_ContentHost添加事件呢?

    谢谢

    2016年5月16日 1:02

答案

  • 您好 skczjun,

    >>"请教一下,如果是.net4.5框架的话 怎么给PART_ContentHost添加事件呢?"

    我试了下,在.NET 4.0中也是不可以的。因为WPF不允许我们在控件模板中为控件添加事件。不过我们有两种替代的解决方案。

    第一种方法. 在控件模板中添加的控件,都可以在Visual Tree中找到。所以我们可以在Window的Loaded事件中找个这个控件,并且为它添加事件。以下代码供你参考。

    //在Window的loaded事件中找到模板中控件,并为之添加事件。
    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        var scroll = GetVisualChild<ScrollViewer>(rtb);
        scroll.Loaded += scroll_Loaded;
    }
    
    void scroll_Loaded(object sender, RoutedEventArgs e)
    {
    
    }
    //根据类型来找到Visual Tree中的控件。
    private static T GetVisualChild<T>(DependencyObject parent) where T : Visual
    {
        T child = default(T);
    
        int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
        for (int i = 0; i < numVisuals; i++)
        {
            Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
            child = v as T;
            if (child == null)
            {
                child = GetVisualChild<T>(v);
            }
            if (child != null)
            {
                break;
            }
        }
        return child;
    }

    第二种方法,我们可以重写控件的OnApplyTemplate方法。在这个方法中,我们可以根据模板中控件的名称来获取模板中的控件,然后就可以为这个控件添加事件了。这种方法我们必须要自定义一个控件来继承系统提供的控件。以下代码供您参考。

    public class MyRichTextBox : RichTextBox
    {
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            var part = GetTemplateChild("PART_ContentHost") as ScrollViewer;
            part.Loaded += part_Loaded;
        }
    
        void part_Loaded(object sender, RoutedEventArgs e)
        {
            
        }
    }
    Best Regards,
    Li Wang

    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    • 已标记为答案 skczjun 2016年5月19日 0:48
    • 取消答案标记 skczjun 2016年5月19日 3:43
    • 已标记为答案 skczjun 2016年5月20日 1:56
    2016年5月17日 3:23

全部回复

  • 您好 skczjun,

    >>"请教一下,如果是.net4.5框架的话 怎么给PART_ContentHost添加事件呢?"

    我试了下,在.NET 4.0中也是不可以的。因为WPF不允许我们在控件模板中为控件添加事件。不过我们有两种替代的解决方案。

    第一种方法. 在控件模板中添加的控件,都可以在Visual Tree中找到。所以我们可以在Window的Loaded事件中找个这个控件,并且为它添加事件。以下代码供你参考。

    //在Window的loaded事件中找到模板中控件,并为之添加事件。
    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        var scroll = GetVisualChild<ScrollViewer>(rtb);
        scroll.Loaded += scroll_Loaded;
    }
    
    void scroll_Loaded(object sender, RoutedEventArgs e)
    {
    
    }
    //根据类型来找到Visual Tree中的控件。
    private static T GetVisualChild<T>(DependencyObject parent) where T : Visual
    {
        T child = default(T);
    
        int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
        for (int i = 0; i < numVisuals; i++)
        {
            Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
            child = v as T;
            if (child == null)
            {
                child = GetVisualChild<T>(v);
            }
            if (child != null)
            {
                break;
            }
        }
        return child;
    }

    第二种方法,我们可以重写控件的OnApplyTemplate方法。在这个方法中,我们可以根据模板中控件的名称来获取模板中的控件,然后就可以为这个控件添加事件了。这种方法我们必须要自定义一个控件来继承系统提供的控件。以下代码供您参考。

    public class MyRichTextBox : RichTextBox
    {
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            var part = GetTemplateChild("PART_ContentHost") as ScrollViewer;
            part.Loaded += part_Loaded;
        }
    
        void part_Loaded(object sender, RoutedEventArgs e)
        {
            
        }
    }
    Best Regards,
    Li Wang

    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    • 已标记为答案 skczjun 2016年5月19日 0:48
    • 取消答案标记 skczjun 2016年5月19日 3:43
    • 已标记为答案 skczjun 2016年5月20日 1:56
    2016年5月17日 3:23
  • 我在.net4.0是可以直接添加的啊。你应用程序目标框架先选.net4.0然后给RichTextBox添加Style后就可以直接添加事件了

    你提供的这2种方法我尝试过 但不是很好用呢

    因为我的Style是经常变动的

    2016年5月19日 3:45
  • 您好 skczjun,

    >>"我在.net4.0是可以直接添加的啊。你应用程序目标框架先选.net4.0然后给RichTextBox添加Style后就可以直接添加事件了"

    我的就是先选.net 4.0, 然后在控件上添加style的。这样编译后报错的。这种方式在WPF中是禁止的。

    >>"因为我的Style是经常变动的"

    我们并不一定要通过重写控件的Template来完成业务需求,您也可以试试用户控件。

    Best Regards,
    Li Wang


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    2016年5月19日 5:16