【问题标题】:Can't apply style to RichTextBox elements based on DependencyProperty无法基于 DependencyProperty 将样式应用于 RichTextBox 元素
【发布时间】:2017-02-09 21:06:13
【问题描述】:

我有一个继承RichTextBox(我将其称为MyRichTextBox)的控件,其中DependencyProperty 定义了某些文本元素类型的样式。与ItemsControl.ItemContainerStyle 类似,此样式将在每个实例的基础上应用于它的一些子级。

我尝试过两种不同的方法,但两种方法都不起作用:

  1. 在创建文本元素(继承Button 并托管在InlineUIContainer 中的控件;我们称之为MyTextElement)时,我将创建基于MyRichTextBox.ItemContainerStyle 的新样式并分配@ 987654329@新款式。
  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>

这应该允许我在MyRichTextBox 中为MyTextElement 类型的所有元素定义样式。方法 #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>

【问题讨论】:

    标签: c# wpf xaml richtextbox dependency-properties


    【解决方案1】:

    您只能将具有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的孩子;最终,样式需要应用于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));
    

    【讨论】:

    • 对,但是Resources.Remove(OldValue.TargetType) 行确保之前使用该键添加的任何样式(始终具有相同的目标类型)在添加新样式之前被删除。如果我没有先删除旧资源,我应该会收到 Item has already been added 错误,但事实并非如此。另外,MyTextElement继承Button,被赋值为InlineUIContainer的child;最终,样式需要应用于MyTextElement,而不是Run。你的 MyTextElement 继承了 Run 并且不是任何东西的孩子。
    • 更新了 OP 以澄清。
    • 它仍然有效。请参阅我的编辑。而且应该删除的不是 Resources.Remove ... 行,而是对 Resources.Add 的第一次调用。
    • 刚刚发现我的问题与无法找到的恶意图像有关。无论如何都将其标记为答案,因为它确实有效!
    • 是的,这正是我正在做的。我定义了一个ContentTemplate,它引用了一个不存在的图像,并且只有在我删除它并使用你的样本后才意识到这一点。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-23
    • 2010-12-22
    相关资源
    最近更新 更多