繁体   English   中英

无法将样式应用于基于DependencyProperty的RichTextBox元素

[英]Can't apply style to RichTextBox elements based on DependencyProperty

我有一个控件,该控件继承了带有DependencyProperty RichTextBox (我将其称为MyRichTextBox ),该MyRichTextBox为某些文本元素类型定义了样式。 ItemsControl.ItemContainerStyle相似,此样式将根据实例应用于其某些子项。

我尝试过两种不同的方法,但两种方法均无效:

  1. 当创建文本元素(即继承的控制Button ,并在托管InlineUIContainer ,我们会打电话给这个MyTextElement ),我想创建一个基于新的风格MyRichTextBox.ItemContainerStyle并分配MyTextElement新样式。
  2. MyRichTextBox.ItemContainerStyle更改时,基于MyRichTextBox.ItemContainerStyle创建新样式,然后添加到MyRichTextBox的资源中。

两种方法都会导致以下意外异常:

An unhandled exception of type 'MS.Internal.PtsHost.UnsafeNativeMethods.PTS.SecondaryException' occurred in PresentationFramework.dll

没有提供任何其他信息,并且在研究此异常时,我还没有发现任何东西,因为它与RichTextBox或以编程方式分配样式有关。 一些文章指出该错误是线程问题。 但是,我并不想在不同的线程创建样式和创建/分配样式而不使其基于MyRichTextBox.ItemContainerStyle 确实工作。

这是使用方法2的控件的外观(为简洁起见,我将方法1排除在外了,因为它做同样的事情,只是方式不同):

public class MyRichTextBox : RichTextBox
{
    public static DependencyProperty ItemContainerStyleProperty = DependencyProperty.Register("ItemContainerStyle", typeof(Style), typeof(MyRichTextBox), new FrameworkPropertyMetadata(default(Style), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnItemContainerStyleChanged));
    public Style ItemContainerStyle
    {
        get
        {
            return (Style)GetValue(ItemContainerStyleProperty);
        }
        set
        {
            SetValue(ItemContainerStyleProperty, value);
        }
    }
    static void OnItemContainerStyleChanged(DependencyObject Object, DependencyPropertyChangedEventArgs e)
    {
        (Object as MyRichTextBox).OnItemContainerStyleChanged((Style)e.OldValue, (Style)e.NewValue);
    }

    protected virtual void OnItemContainerStyleChanged(Style OldValue, Style NewValue)
    {
        //Make sure the old style is gone
        if (OldValue != null)
            Resources.Remove(OldValue.TargetType);

        if (NewValue != null)
        {
            //This line does not attempt to utilize the specified style, but is stable
            Resources.Add(NewValue.TargetType, new Style(NewValue.TargetType));

            //This line attempts to utilize the specified style, but is unstable
            Resources.Add(NewValue.TargetType, new Style(NewValue.TargetType, NewValue));
        }
    }
}

最终,我希望能够做到这一点:

<Controls:MyRichTextBox>
    <Controls:MyRichTextBox.ItemContainerStyle>
        <Style TargetType="{x:Type Controls:MyTextElement}">
            <!-- Whatever... -->
        </Style>
    </Controls:MyRichTextBox.ItemContainerStyle>
</Controls:MyRichTextBox>

这应该允许我为MyTextElement中的MyRichTextBox类型的所有元素定义样式。 方法1会给出相同的结果,但是两种方法都将失败,并出现相同的错误。

因为在基于MyRichTextBox.ItemContainerStyle 情况下分配新样式有效,所以不清楚导致错误的原因是我做错了什么。

编辑MyTextElement看起来像这样:

public class MyTextElement : Button
{
    public MyTextElement() : base()
    {
    }
}

MyRichTextBox有效逻辑结构如下所示:

<Controls:MyRichTextBox>
    <FlowDocument>
        <Paragraph>
            <InlineUIContainer>
                <Controls:MyTextElement Content="My Content"/>
            </InlineUIContainer>
         </Paragraph >
     </FlowDocument>
 </Controls:MyRichTextBox>

您只能将具有NewValue.TargetType键的一个资源添加到ResourceDictionary

以下示例代码对我来说很好用:

public class MyTextElement : Run { }

public class MyRichTextBox : RichTextBox
{
    public static DependencyProperty ItemContainerStyleProperty = DependencyProperty.Register("ItemContainerStyle", typeof(Style), typeof(MyRichTextBox), new FrameworkPropertyMetadata(default(Style), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnItemContainerStyleChanged));
    public Style ItemContainerStyle
    {
        get
        {
            return (Style)GetValue(ItemContainerStyleProperty);
        }
        set
        {
            SetValue(ItemContainerStyleProperty, value);
        }
    }
    static void OnItemContainerStyleChanged(DependencyObject Object, DependencyPropertyChangedEventArgs e)
    {
        (Object as MyRichTextBox).OnItemContainerStyleChanged((Style)e.OldValue, (Style)e.NewValue);
    }

    protected virtual void OnItemContainerStyleChanged(Style OldValue, Style NewValue)
    {
        //Make sure the old style is gone
        if (OldValue != null)
            Resources.Remove(OldValue.TargetType);

        if (NewValue != null)
        {
            //This line does not attempt to utilize the specified style, but is stable
            //Resources.Add(NewValue.TargetType, new Style(NewValue.TargetType));

            //This line attempts to utilize the specified style, but is unstable
            Resources.Add(NewValue.TargetType, new Style(NewValue.TargetType, NewValue));
        }
    }
}

<Controls:MyRichTextBox>
    <Controls:MyRichTextBox.ItemContainerStyle>
        <Style TargetType="{x:Type Controls:MyTextElement}">
            <Setter Property="Foreground" Value="Red" />
        </Style>
    </Controls:MyRichTextBox.ItemContainerStyle>
    <FlowDocument>
        <Paragraph>
            <Run Text="default" />
            <Controls:MyTextElement Text="red" />
        </Paragraph>
    </FlowDocument>
</Controls:MyRichTextBox>

在此处输入图片说明

编辑:

MyTextElement继承Button并被分配为InlineUIContainer的子InlineUIContainer 最终,样式需要应用于MyTextElement ,而不是Run 您的MyTextElement继承Run ,不是任何子项

这也可以:

public class MyTextElement : Button
{
    public MyTextElement() : base()
    {
    }
}

public class MyRichTextBox : RichTextBox
{
    public static DependencyProperty ItemContainerStyleProperty = DependencyProperty.Register("ItemContainerStyle", 
        typeof(Style), typeof(MyRichTextBox), new FrameworkPropertyMetadata(default(Style), 
            FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnItemContainerStyleChanged));
    public Style ItemContainerStyle
    {
        get
        {
            return (Style)GetValue(ItemContainerStyleProperty);
        }
        set
        {
            SetValue(ItemContainerStyleProperty, value);
        }
    }
    static void OnItemContainerStyleChanged(DependencyObject Object, DependencyPropertyChangedEventArgs e)
    {
        (Object as MyRichTextBox).OnItemContainerStyleChanged((Style)e.OldValue, (Style)e.NewValue);
    }

    protected virtual void OnItemContainerStyleChanged(Style OldValue, Style NewValue)
    {
        //Make sure the old style is gone
        if (OldValue != null)
            Resources.Remove(OldValue.TargetType);

        if (NewValue != null)
        {
            Resources.Add(NewValue.TargetType, new Style(NewValue.TargetType, NewValue));
        }
    }
}

<Controls:MyRichTextBox IsDocumentEnabled="True">
    <Controls:MyRichTextBox.ItemContainerStyle>
        <Style TargetType="{x:Type Controls:MyTextElement}">
            <Setter Property="Foreground" Value="Red" />
        </Style>
    </Controls:MyRichTextBox.ItemContainerStyle>
    <FlowDocument>
        <Paragraph>
            <InlineUIContainer>
                <Controls:MyTextElement Content="My Content"/>
            </InlineUIContainer>
        </Paragraph >
    </FlowDocument>
</Controls:MyRichTextBox>

注意我从OnItemContainerStyleChanged方法中删除了以下行:

Resources.Add(NewValue.TargetType, new Style(NewValue.TargetType));

在此处输入图片说明

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM