You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Caliburn Micro+WinRT下RichEditBox双向绑定失效问题排查

解决WinRT RichEditBox与Caliburn Micro双向绑定失效问题

我之前也碰到过这个情况——RichEditBox没有现成的Text属性用来绑定,用附加属性做单向绑定没问题,但编辑后同步不回ViewModel,确实头疼。结合Caliburn Micro和WinRT的特性,给你一套可行的方案:

核心思路

RichEditBox的内容存在Document属性里,我们需要用附加属性作为中间层,同时处理两个方向的同步:

  • 从ViewModel到View:把ViewModel的字符串属性转成RichEditBox的Document内容
  • 从View到ViewModel:监听RichEditBox的内容变化,把Document转成字符串更新附加属性,进而同步到ViewModel

步骤1:实现附加属性辅助类

创建一个静态辅助类,封装附加属性和同步逻辑:

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Documents;

public static class RichEditBoxBindingHelper
{
    // 定义附加属性:绑定的内容字符串(支持RTF或纯文本)
    public static readonly DependencyProperty BindableContentProperty =
        DependencyProperty.RegisterAttached(
            "BindableContent",
            typeof(string),
            typeof(RichEditBoxBindingHelper),
            new PropertyMetadata(null, OnBindableContentChanged));

    public static string GetBindableContent(DependencyObject obj)
    {
        return (string)obj.GetValue(BindableContentProperty);
    }

    public static void SetBindableContent(DependencyObject obj, string value)
    {
        obj.SetValue(BindableContentProperty, value);
    }

    // 处理附加属性变化(ViewModel -> View)
    private static void OnBindableContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is not RichEditBox richEditBox) return;

        // 先移除事件监听,避免设置内容时触发反向同步导致循环
        richEditBox.TextChanged -= RichEditBox_ContentChanged;

        var newContent = e.NewValue as string;
        if (!string.IsNullOrEmpty(newContent))
        {
            // 这里用RTF格式,要纯文本就换成FormatPlainText
            richEditBox.Document.SetText(TextSetOptions.FormatRtf, newContent);
        }

        // 重新注册事件,监听用户编辑操作
        richEditBox.TextChanged += RichEditBox_ContentChanged;
    }

    // 处理RichEditBox内容变化(View -> ViewModel)
    private static void RichEditBox_ContentChanged(object sender, RoutedEventArgs e)
    {
        if (sender is not RichEditBox richEditBox) return;

        // 把Document内容转成字符串(和上面的格式保持一致)
        richEditBox.Document.GetText(TextGetOptions.FormatRtf, out string currentContent);
        // 更新附加属性,触发ViewModel的绑定更新
        SetBindableContent(richEditBox, currentContent);
    }
}

步骤2:ViewModel配置

确保你的ViewModel继承自Caliburn Micro的PropertyChangedBase(或Screen),并定义绑定属性:

using Caliburn.Micro;

public class YourViewModel : PropertyChangedBase
{
    private string _editorContent;
    // 绑定的内容属性,初始值会同步到RichEditBox
    public string EditorContent
    {
        get => _editorContent;
        set
        {
            if (_editorContent != value)
            {
                _editorContent = value;
                NotifyOfPropertyChange(() => EditorContent);
            }
        }
    }

    // 可以在构造函数里设置初始值测试
    public YourViewModel()
    {
        EditorContent = @"{\rtf1\ansi\deff0 {\colortbl ;\red255\green0\blue0;} This is \cf1 red text\cf0 !}";
    }
}

步骤3:XAML绑定

在XAML里引用辅助类,给RichEditBox设置附加属性的双向绑定:

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:YourNamespace"
    xmlns:cal="http://www.caliburnproject.org">

    <RichEditBox 
        local:RichEditBoxBindingHelper.BindableContent="{Binding EditorContent, Mode=TwoWay}"
        Width="400" Height="200"/>
</Page>

关键注意点

  1. 避免循环更新:在更新RichEditBox内容前先移除TextChanged监听,设置完成后再重新注册——不然ViewModel更新属性时,会触发RichEditBox的内容变化事件,又把值同步回去,造成循环。
  2. 格式一致性:SetText和GetText的格式参数要保持一致(要么都用RTF,要么都用纯文本),不然内容会乱码或丢失格式。
  3. Caliburn Micro支持:Caliburn Micro对DependencyProperty的双向绑定完全兼容,只要你显式设置Mode=TwoWay,并且ViewModel正确触发NotifyOfPropertyChange。

这样配置后,初始值会正常显示,用户编辑RichEditBox的内容后,也会实时同步回ViewModel的EditorContent属性。

内容的提问来源于stack exchange,提问作者M.kazem Akhgary

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:12:16