Pracuję nad zrobieniem zrzutu ekranu elementu interfejsu użytkownika (WPF) w różnych rozmiarach i jestem w stanie to zrobić za pomocą "RenderTargetBitmap." Ale UIElement
, który ma część Adorner
, nie przyjdzie podczas kopiowania. Co powinienem zrobić, aby to osiągnąć Jakieś odniesienie lub fragment kodu?Kopiowanie elementu interfejsu użytkownika z adornerem
Odpowiedz
Z tego co wiem, elementy nie mają bezpośrednich odniesień do ich adoratorów, ale adoratorzy odnoszą się do ich elementu poprzez AdornedElement, więc można szukać adorners przypisany do Twojego elementu w ten sposób:
var layer = AdornerLayer.GetAdornerLayer(element);
var adorners = layer.GetVisualChildren().Cast<Adorner>().Where(a => a.AdornedElement == element);
Tutaj GetVisualChildren
stanowi metodę rozszerzenia, które określa się jako:
public static IEnumerable<DependencyObject> GetVisualChildren(this DependencyObject current) {
return Enumerable.Range(0, VisualTreeHelper.GetChildrenCount(current)).Select(i => VisualTreeHelper.GetChild(current, i));
}
Wielkość adorner wydaje się obejmować rozmiar elementu zdobi (choć nie jestem pewien, czy to zawsze tak jest), więc jeśli nie ma tylko jeden adorner, czyli twój rozmiar ekranu. Jeśli jest więcej niż jeden adorner, musisz znaleźć maksymalną wartość dla każdej granicy (lewy, górny, prawy, dolny), aby obliczyć region zrzutu ekranu.
Będziesz musiał przechwycić AdornerDecorator
, który zawiera zarówno elementy ozdabiane, jak i AdornerLayer
(layer
w powyższym kodzie). To byłby wizualny rodzic warstwy:
var container = VisualTreeHelper.GetParent(layer) as Visual;
Gdy masz pojemnik, można uczynić go RenderTargetBitmap
i przyciąć go do obszaru ekranu.
Dla regionu zrzutu ekranu wymagane są ograniczenia elementów względem kontenera. Po pierwsze, uzyskać non-względne granice:
var elementBounds = element.RenderTransform.TransformBounds(new Rect(element.RenderSize));
Następnie dostać te granice względem pojemnika:
var relativeElementBounds = element.TransformToAncestor(container).TransformBounds(elementBounds);
Jak już wspomniano wyżej, trzeba będzie to zrobić dla elementu, jak każdy z jego adorners i połączyć maksymalne granice w jeden końcowy Rect, który jest wystarczająco duży, aby pomieścić wszystkie z nich.
Wreszcie, należy CroppedBitmap dostać przyciętej wersji RenderTargetBitmap
:
var croppedBitmap = new CroppedBitmap(renderTargetBitmap, new Int32Rect(left, top, width, height));
CroppedBitmap
i RenderTargetBitmap
zarówno dziedziczyć BitmapSource
, więc powinieneś być w stanie go uratować w ten sam sposób.
Można używać rodzimych WPF Printing przestrzeń nazw, aby wydrukować do pliku XPS i będzie obejmować adorner w wyniku (ja testowałem to z powodzeniem) ...
using System.Windows.Controls;
private void ExecutePrintCommand(object obj)
{
PrintDialog printDialog = new PrintDialog();
if (printDialog.ShowDialog() == true)
{
printDialog.PrintVisual(_mainWindow, "Main Window with Adorner");
}
}
Jeśli nie chcą użyj PrintDialog (który faktycznie otwiera okno dialogowe). Możesz użyć klasy XpsDocumentWriter, aby programowo sterować procesem. Umożliwianie fragment tego jest ...
XpsDocumentWriter xpsdw = PrintQueue.CreateXpsDocumentWriter(q);
xpsdw.Write(viewer.Document);
... która została pozyskana z tutaj: Print FixedDocument programmatically I istnieje więcej artykułów o dopracowanie procesu, jeśli jest to część wymagań.Zauważ, że plik XPS jest w rzeczywistości plikiem "zip" podszywającym się pod plik "xps", więc możesz go rozpakować, zmieniając rozszerzenie, aby sprawdzić, czy zawartość jest w jakikolwiek sposób użyta.
wtórnie Testowałem zapisywania okno z adorner na TextBox z tym kodem ...
private void SaveWithAdorner()
{
RenderTargetBitmap rtb = RenderVisaulToBitmap(_mainWindow, 500, 300);
MemoryStream file = new MemoryStream();
BitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtb));
encoder.Save(file);
using (FileStream fstream = File.OpenWrite("Myimage.jpg"))
{
file.WriteTo(fstream);
fstream.Flush();
fstream.Close();
}
}
... z dobrymi wynikami. Tj. Adorner pojawił się w zapisanej mapie bitowej z czerwoną obwódką. Może to różnić się od twojego kodu, ponieważ używam enkodera Png (ale zapisałem go do pliku "jpg").
Mimo że pomyślnie przetestowałem oba podejścia, musisz sprawdzić je na swoim sprzęcie.
I wreszcie, jako ośrodek ostatniej szansy, można wyłączyć tryb renderowania sprzętu WPF i ustawić go do renderowania programowego ...
RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;
..., dla których nie jest to miłe SO wątku tutaj: Software rendering mode - WPF
+1 za wyświetlenie sposobu renderowania i zapisywania bitmapy. Problem z adoratorami polega na tym, że są umieszczani na warstwie pierwszego planu, a nie w wizualnym drzewie elementu, który zdobią. Oznacza to, że pojawią się, gdy wyrenderujesz całe okno, ale nie podczas renderowania pojedynczego ozdobnego elementu - tak więc przechwytywanie pojedynczego elementu można uzyskać poprzez przycięcie całej bitmapy. – nmclean
W moim przypadku wszystko, co potrzebne było nazwać AdornerLayer klasa tak:
public void GetScreenshotWithAdorner(Canvas canvas, string filename)
{
AdornerLayer adornerlayer = AdornerLayer.GetAdornerLayer(canvas);
RenderTargetBitmap rtb = new RenderTargetBitmap(
(int)canvas.ActualWidth,
(int)canvas.ActualHeight,
96, //dip X
96, //dpi Y
PixelFormats.Pbgra32);
rtb.Render(canvas); //renders the canvas screen first...
rtb.Render(adornerlayer); //... then it renders the adorner layer
SaveRTBAsPNG(rtb, filename);
}
private void SaveRTBAsPNG(RenderTargetBitmap bmp, string filename)
{
PngBitmapEncoder pngImage = new PngBitmapEncoder();
pngImage.Frames.Add(BitmapFrame.Create(bmp));
using (var filestream = System.IO.File.Create(filename))
{
pngImage.Save(filestream);
}
}
Działa to, jeśli chcesz dołączyć WSZYSTKICH adoratorów do swojego płótna.
- 1. Najlepszy sposób wibrowania elementu interfejsu użytkownika?
- 2. Kopiowanie MySQLa użytkownika
- 3. Plik R.java nie aktualizuje się z identyfikatorem elementu interfejsu użytkownika
- 4. Ładowanie elementu iframe wewnątrz okna dialogowego interfejsu użytkownika nie działa
- 5. Wyrównanie pionowe elementu div przy użyciu semantycznego interfejsu użytkownika
- 6. Jak uzyskać wartość obrotu elementu interfejsu użytkownika w WPF
- 7. Tworzenie projektanta interfejsu użytkownika
- 8. Testowanie rozszerzenia czynności z testami interfejsu użytkownika
- 9. Dystrybucja zaćmienia z dostosowaniami interfejsu użytkownika
- 10. Zamrażanie interfejsu użytkownika z asynchronizacją/oczekiwaniem
- 11. Usuwanie zadań z interfejsu użytkownika Oozie?
- 12. Wejście interfejsu użytkownika z reaktywnym bananem-wx
- 13. Dlaczego zawsze należy tworzyć/aktualizować elementy interfejsu użytkownika z wątku interfejsu użytkownika?
- 14. Projekt interfejsu użytkownika w Flex
- 15. Zamknij okno dialogowe interfejsu jQuery z elementu wewnątrz niego?
- 16. Ograniczenia interfejsu YouTube dla użytkownika
- 17. Angularjs jquery Autouzupełnianie interfejsu użytkownika
- 18. Zestawy dostosowywania interfejsu użytkownika iOS?
- 19. Niestandardowa kontrola segmentowa interfejsu użytkownika
- 20. Semantylny pasek postępu interfejsu użytkownika
- 21. Zadanie i odblokowanie interfejsu użytkownika
- 22. Kolor interfejsu użytkownika w Eclipse
- 23. Jak nazywasz elementy interfejsu użytkownika?
- 24. Okno przełącznika automatyzacji interfejsu użytkownika
- 25. Problemy z haftowaniem interfejsu użytkownika z układem marionetek kręgosłupa
- 26. Łączenie menu przesuwanego interfejsu użytkownika z interfejsem myszy z nawigacją
- 27. WPF: Kopiowanie z DataGrid
- 28. Wygląd szablonu interfejsu użytkownika - typowe elementy interfejsu użytkownika we wszystkich scenach aplikacji iOs?
- 29. Czy w QT można określić różne układy interfejsu użytkownika dla różnych stylów interfejsu użytkownika?
- 30. Pokaż etykietkę narzędzia tylko wtedy, gdy tekst jest ucięty w ustawieniu kątowym interfejsu użytkownika interfejsu użytkownika
cóż, da to adorner, ale muszę zrobić zrzut ekranu całości. W tym przypadku muszę wykonać migawkę z dwóch różnych kontrolek i trzeba zintegrować dwa obrazy jeden na górze z dużą ilością złożoności, jak znalezienie lokalizacji do przeszłości obrazu adornera ..... – Mohanavel
@Mohanavel Musisz uchwycić cały element nadrzędny a następnie wybierz z niego region, w którym znajdują się kontrolki. Okazuje się, że jest to bardziej skomplikowane, niż początkowo sądziłem, więc zredagowałem mój post bardziej szczegółowo. – nmclean