windows phone 8.1 - Cómo establecer enlaces múltiples en RichEditBox sin AccessViolationException
windows-phone-8.1 (1)
Esta solución fue publicada en los foros de MSDN por Eric Fleck y funcionó para mí:
RtfBox.Document.Selection.StartPosition = RtfBox.Document.Selection.EndPosition = range.StartPosition;
range.Link = link;
RtfBox.Document.Selection.StartPosition = RtfBox.Document.Selection.EndPosition = range.EndPosition;
Parecía que era importante hacerlo en cada enlace que se establecía, porque a menos que esté muy equivocado lo intenté antes de actualizar todos mis enlaces y no sirvió de nada.
Todavía no estoy usando la capacidad de restaurar la selección a su ubicación original, pero es posible que desee hacerlo en el futuro, así que hice esta pequeña clase de utilidad. También para que pueda envolver lugares como estos en un bloque using () para un poco de azúcar sintáctico.
public static class ITextDocumentExtensions
{
public static IDisposable SuppressSelection(this ITextDocument document)
{
var start = document.Selection.StartPosition;
var end = document.Selection.EndPosition;
var disposable = new ActionDisposable(() => document.Selection.SetRange(start, end));
document.Selection.SetRange(0, 0);
return disposable;
}
private sealed class ActionDisposable : IDisposable
{
private readonly Action dispose;
public ActionDisposable(Action dispose)
{
this.dispose = dispose;
}
public void Dispose()
{
dispose();
}
}
}
Lo cual me permite escribir
using (RtfBox.Document.SuppressSelection())
{
range.Link = link;
}
Básicamente, mi problema es que recibo AccessViolationException cuando trato de aplicar mediante programación más de 2 enlaces a ITextDocument, si un usuario ha editado el contenido. He creado una sencilla aplicación de demostración, basada en la plantilla de la aplicación en blanco de Windows phone (8.1).
Yo agrego a la página principal:
<StackPanel Margin="19,0,0,0">
<Button
Content="Apply Links"
Click="Button_Click"
/>
<RichEditBox
x:Name="RtfBox"
Height="300"
Loaded="RtfBox_Loaded"
Margin="0,0,19,0"
TextWrapping="Wrap"
/>
</StackPanel>
Y al código detrás para la misma página que agrego (usando declaraciones no incluidas):
private void RtfBox_Loaded(object sender, RoutedEventArgs e)
{
//RtfBox.Document.SetText(TextSetOptions.None, "Links to demo, example, test. More links to demo, demo, example, test and test.");
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var pages = new Dictionary<Guid, string> { { Guid.NewGuid(), "demo" }, { Guid.NewGuid(), "example" }, { Guid.NewGuid(), "test" } };
// NOTE: Avoid performance implications of many small updates
RtfBox.Document.BatchDisplayUpdates();
ITextRange range;
foreach (var page in pages)
{
var link = string.Format("/"richtea.demo://pages/{0}/"", page.Key);
var skip = 0;
while ((range = RtfBox.Document.GetRange(skip, TextConstants.MaxUnitCount)).FindText(page.Value, TextConstants.MaxUnitCount, FindOptions.None) != 0)
{
if (range.Link == "")
{
// TODO: Stop this throw exceptions
System.Diagnostics.Debug.WriteLine("Setting text at position {0} to link: ''{1}''.", range.StartPosition, link);
range.Link = link;
}
skip = range.EndPosition;
}
}
RtfBox.Document.ApplyDisplayUpdates();
}
Si inicia esto y escribe algo como "Un enlace a la página de demostración" y hace clic en el botón, se convierte en un enlace correctamente. Puede seguir poniendo el mismo texto y hacer clic en el botón, y continúa funcionando.
Sin embargo, si agrega tres o más (por alguna razón para mí, siempre son 3 o más) de las palabras demostración , ejemplo o prueba (mis palabras clave) y presiona el botón, se AccessViolationException
un AccessViolationException
en AccessViolationException
al establecer range.Link = link
. Vale la pena señalar si comprueba durante la depuración, la propiedad range.Link realmente se ha configurado.
Lo que es más interesante, si descomenta los contenidos de RtfBox_Loaded
, ejecuta la aplicación y hace clic en el botón de inmediato, lo maneja bien. ¿Entonces parece relacionarse con la selección que se ha establecido en RichEditBox? Intenté desactivar el control antes de aplicar los enlaces, pero eso no me ayudó.
Algunas otras cosas que me han dificultado diagnosticar el problema aquí incluyen:
- Parece funcionar más a menudo si estoy depurando línea por línea, por lo que podría estar relacionado con el tiempo también
- No puedo usar el ITextDocument no en el subproceso de la interfaz de usuario parece (el objeto COM no se puede transmitir) así que si bien parece que la asincronización podría ser un mejor enfoque, no lo he logrado aquí.
También para el registro, la razón por la que intento hacer todas las actualizaciones en masa, en lugar de que el usuario las escriba, es que no quiero ocuparme de la limpieza cuando las notas se renombran o eliminan, y no lo hago. realmente quiero esos enlaces en tiempo de edición o guardados, pero podría vivir con el más tarde.