2009-12-28 11 views
10

necesito para que las áreas de XAML imprimible y también lo han hecho hacer este controlador de botón:¿Existe una manera fácil/integrada de obtener una copia exacta (clon) de un elemento XAML?

private void Button_Click_Print(object sender, RoutedEventArgs e) 
{ 
    Customer.PrintReport(PrintableArea); 
} 

Y en PrintReport EMBALO la FrameworkElement en otros elementos con el fin de imprimirla en un poco diferente manera que que está en la pantalla, así:

public void PrintReport(FrameworkElement fwe) 
{ 
    StackPanel sp = new StackPanel(); 
    sp.Children.Add(fwe); 
    TextBlock tb = new TextBlock(); 
    tb.Text = "hello"; 
    sp.Children.Add(tb); 

    PrintDialog dialog = new PrintDialog(); 
    if (dialog.ShowDialog() == true) 
    { 
     dialog.PrintVisual(sp, "Print job"); 
    } 
} 

Pero lo anterior me da el error siguiente :

El elemento especificado ya es el hijo lógico de otro elemento. Desconéctelo primero.

¿Hay una manera fácil de clonar el FrameworkElement para que pueda manipular la copia, impresión, y luego olvidarse de él, dejando el elemento original en el XAML que se muestra en la pantalla intacta?

Algo como esto me imaginaría:

FrameworkElement fwe2 = FrameworkElement.Clone(fwe); //pseudo-code 

Respuesta

-1

Estoy seguro de que debe haber manera fácil de hacer la copia (aparte de desprenderse de los padres, la impresión y fijación de la espalda). Por ejemplo, puede intentar XamlWriter escribir xaml, y luego leerlo nuevamente a través de XamlReader. Pero sospecho que puede haber algunos errores vinculantes y de diseño de esta manera.

En su lugar, trataría de usar WriteableBitmap para tomar una instantánea del área imprimible e imprimirla. De esta manera creas un vector raster y suelto, pero no soy lo suficientemente bueno para imprimir si es bueno o malo. De todos modos podrías intentar y verificar :).

Cheers, Anvaka.

6

Tuve un problema similar en mi proyecto actual y lo resolví con este código.

public static class ExtensionMethods 
{ 
    public static T XamlClone<T>(this T original) 
     where T : class 
    { 
     if (original == null) 
      return null; 

     object clone; 
     using (var stream = new MemoryStream()) 
     { 
      XamlWriter.Save(original, stream); 
      stream.Seek(0, SeekOrigin.Begin); 
      clone = XamlReader.Load(stream); 
     } 

     if (clone is T) 
      return (T)clone; 
     else 
      return null; 
    } 
} 

De esta manera aparece simplemente como un método en todos los objetos en su proyecto de WPF, que no es necesario dar ningún parámetro al método y devuelve un objeto de la misma clase que el original.

+4

Existen limitaciones en este enfoque. Vea http://msdn.microsoft.com/en-us/library/ms754193.aspx. – JeffFerguson

+0

Si desea restaurar el elemento al mismo tamaño, vuelva a llamar 'clone.Arrange (New Rect (0, 0, orginal.ActualWidth, orginal.ActualHeight))' y 'clone.UpdateLayout()', pero primero debe realizar el reparto a un 'UIElement'. – Peter

3

En WPF, copiar (o "clonar") elementos casi nunca es correcto. Esto efectivamente hace que esto sea una pregunta XY Problem. Es decir. usted solo piensa que necesita literalmente clonar los elementos en su árbol visual. Pero tú no.

El enfoque idiomático y correcto aquí es declarar DataTemplate que representa los datos que desea imprimir. Por supuesto, eso también significa que los datos que desea imprimir están a su vez representados por una clase de modelo de vista, para la cual se ha declarado DataTemplate (es decir, a través de la propiedad DataType).

Por ejemplo:

<DataTemplate DataType={x:Type PrintableViewModel}> 
    <!-- template contents go here --> 
</DataTemplate> 

El ser PrintableViewModel clase, por supuesto, una clase de vista del modelo que contiene los datos que desea utilizar para rellenar el árbol visual que será impreso.

En el XAML para su interfaz de usuario, usted entonces lo usan algo como esto:

<ContentControl Content={Binding PrintableViewModelProperty}/> 

es decir, Vincular la propiedad Content a una propiedad en el objeto actual DataContext que devuelve una instancia de su PrintableViewModel, y dejar que el ContentControl muestre los datos de manera apropiada.

WPF buscará la plantilla de datos adecuada y la aplicará para visualizarla en el ContentControl. Cuando desee imprimir los datos, a continuación, sólo hacer algo como esto:

PrintDialog printDialog = new PrintDialog(); 

if (printDialog.ShowDialog() == true) 
{ 
    ContentControl contentControl = new ContentControl { Content = ((ViewModelClass)DataContext)PrintableViewModelProperty}; 

    // This part with the margins is not strictly relevant to your question per se, 
    // but it's useful enough to be worth including here for future reference 
    PageImageableArea area = printDialog.PrintQueue.GetPrintCapabilities(printDialog.PrintTicket).PageImageableArea; 

    contentControl.Margin = new Thickness(area.OriginWidth, area.OriginHeight, 
     printDialog.PrintableAreaWidth - area.ExtentWidth - area.OriginWidth, 
     printDialog.PrintableAreaHeight - area.ExtentHeight - area.OriginHeight); 

    // This shows retrieving the data template which is declared using the DataType 
    // property. Of course, if you simply declare a key and reference it explicitly 
    // in XAML, you can just use the key itself here. 
    DataTemplateKey key = new DataTemplateKey(typeof(MazeViewModel)); 

    contentControl.ContentTemplate = (DataTemplate)FindResource(key); 
    printDialog.PrintVisual(contentControl, "MazeGenerator"); 
} 

Esto hará que WPF para reutilizar de forma automática la plantilla que ya se ha descrito para la clase PrintableViewModel, poblando el ContentControl 's visual subárbol de acuerdo con esa plantilla, duplicando el visual que se muestra en la pantalla, pero sin tener que hacer ningún tipo de clonación explícita de elementos de la interfaz de usuario.


Lo anterior ilustra cómo reutilizar exactamente la representación visual. Pero, por supuesto, si desea personalizar la salida con el fin de imprimir, es tan simple como declarar que se usa un DataTemplate diferente cuando imprime.

Cuestiones relacionadas