2008-08-28 18 views

Respuesta

53

La forma más sencilla que lo he hecho es usar un XamlWriter para guardar el objeto WPF como una cadena. El método Save serializará el objeto y todos sus elementos secundarios en el árbol lógico. Ahora puede crear un nuevo objeto y cargarlo con un XamlReader.

ejemplo: escribir el objeto a xaml (digamos que el objeto era un control de cuadrícula):

string gridXaml = XamlWriter.Save(myGrid); 

cargarlo en un nuevo objeto:

StringReader stringReader = new StringReader(gridXaml); 
XmlReader xmlReader = XmlReader.Create(stringReader); 
Grid newGrid = (Grid)XamlReader.Load(xmlReader); 
+1

Tenga en cuenta que también clona el nombre que complica su uso para la interfaz de usuario Elementos si han de ser colocados es el mismo contenedor raíz. – toad

+0

No creo esto preserva las animaciones, ¿o sí? –

+7

Para ser claros, esto es solo la mitad de la solución (como quedó atrás en 08). Esto causará que los enlaces sean evaluados y los resultados sean serializados. Si desea preservar los enlaces (como la pregunta preguntado) usted debe agregar un ExpressionConverter al tipo de enlace en tiempo de ejecución (vea la segunda parte de mi pregunta para el enlace relevante) o vea mi propia respuesta a continuación para saber cómo hacerlo en 4.0. – Will

-1

¿Qué tal:

public static T DeepClone<T>(T from) 
    { 
     using (MemoryStream s = new MemoryStream()) 
     { 
      BinaryFormatter f = new BinaryFormatter(); 
      f.Serialize(s, from); 
      s.Position = 0; 
      object clone = f.Deserialize(s); 

      return (T)clone; 
     } 
    } 

Por supuesto esta profunda clones de cualquier objeto, y puede que no sea la solución más rápida en la ciudad, pero tiene menos mantenimiento .. . :)

+4

Esto no funciona para objetos WPF = ( –

30

En .NET 4.0, el La nueva pila de serialización xaml hace MUCHO más fácil.

var sb = new StringBuilder(); 
var writer = XmlWriter.Create(sb, new XmlWriterSettings 
{ 
    Indent = true, 
    ConformanceLevel = ConformanceLevel.Fragment, 
    OmitXmlDeclaration = true, 
    NamespaceHandling = NamespaceHandling.OmitDuplicates, 
}); 
var mgr = new XamlDesignerSerializationManager(writer); 

// HERE BE MAGIC!!! 
mgr.XamlWriterMode = XamlWriterMode.Expression; 
// THERE WERE MAGIC!!! 

System.Windows.Markup.XamlWriter.Save(this, mgr); 
return sb.ToString(); 
+0

No veo cómo esto es diferente a solo usar XamlWriter.Save? Al menos no vi ningún resultado diferente al tratar de serializar un DataGrid. –

+4

@JP lo siento, esto no es tan claro ... La pregunta era cómo clonar * mientras conservaba las encuadernaciones *. La respuesta marcada es mitad correcta; de hecho, si lo hace, encontrará que sus enlaces serán evaluados y los resultados (no los enlaces) serán serializados.En mi pregunta, agregué la segunda mitad a la solución, que es agregar un ExpressionConverter y agregarlo al tipo de enlace en tiempo de ejecución. Es un poco oscuro. Lo mismo se puede lograr con esta respuesta: ¿ves el comentario HERE BE MAGIC? Eso instruye al serializador ** no ** para evaluar enlaces durante la serialización. Ordenado. – Will

+0

Ya, yo vi esto. Todavía estoy trabajando en el mismo problema con mi Datagrid y no noté ningún resultado diferente con respecto al enlace de datos. Mi Datagrid aún está en blanco. Debo extrañar algo más. No obstante, te daré un voto favorable para señalar todo esto. –

4

Aquí hay algunas buenas respuestas. Muy útil. He intentado varios métodos para copiar información de enlace, incluido el enfoque descrito en http://pjlcon.wordpress.com/2011/01/14/change-a-wpf-binding-from-sync-to-async-programatically/, pero la información aquí es la mejor en Internet.

Creé un método de extensión reutilizable para tratar con InvalidOperationException "El enlace no se puede cambiar después de que se haya utilizado." En mi caso, mantenía algún código que alguien escribió, y después de una importante actualización del framework DevExpress DXGrid, ya no funcionó. Lo siguiente resolvió mi problema perfectamente. La parte del código donde devuelvo el objeto podría ser más agradable, y lo volveré a factorizar más adelante.

/// <summary> 
/// Extension methods for the WPF Binding class. 
/// </summary> 
public static class BindingExtensions 
{ 
    public static BindingBase CloneViaXamlSerialization(this BindingBase binding) 
    { 
     var sb = new StringBuilder(); 
     var writer = XmlWriter.Create(sb, new XmlWriterSettings 
     { 
      Indent = true, 
      ConformanceLevel = ConformanceLevel.Fragment, 
      OmitXmlDeclaration = true, 
      NamespaceHandling = NamespaceHandling.OmitDuplicates, 
     }); 
     var mgr = new XamlDesignerSerializationManager(writer); 

     // HERE BE MAGIC!!! 
     mgr.XamlWriterMode = XamlWriterMode.Expression; 
     // THERE WERE MAGIC!!! 

     System.Windows.Markup.XamlWriter.Save(binding, mgr); 
     StringReader stringReader = new StringReader(sb.ToString()); 
     XmlReader xmlReader = XmlReader.Create(stringReader); 
     object newBinding = (object)XamlReader.Load(xmlReader); 
     if (newBinding == null) 
     { 
      throw new ArgumentNullException("Binding could not be cloned via Xaml Serialization Stack."); 
     } 

     if (newBinding is Binding) 
     { 
      return (Binding)newBinding; 
     } 
     else if (newBinding is MultiBinding) 
     { 
      return (MultiBinding)newBinding; 
     } 
     else if (newBinding is PriorityBinding) 
     { 
      return (PriorityBinding)newBinding; 
     } 
     else 
     { 
      throw new InvalidOperationException("Binding could not be cast."); 
     } 
    } 
} 
Cuestiones relacionadas