Reputation: 135
Hi guys, i've been working and searching for a report using WPF C# and found out one of the a nice report and easy also, found this link and use it. So i tried to use it, pls check my code,
in my EmployeeProfileWindow
in print button,
private void btnprintviolation_Click(object sender, RoutedEventArgs e)
{
ReportViolationWindow NewReportViolationWindow = new ReportViolationWindow();
//Windows.Add(NewReportViolationWindow);
GlobalVar.ViolationEmpNum = txtdispid.Text;
GlobalVar.ViolationRefNumToPrint.Clear();
for (int i = 0; i < lvviolations.Items.Count; i++)
{
GlobalVar.ViolationRefNumToPrint.Add(((EmpViolationObject)lvviolations.Items[i]).VioRefNum);
}
NewReportViolationWindow.Show();
}
So if ever i click the button it will appear a new Window name NewReportViolationWindow
. I'll just copy or edited as what in the open source sample is, in Template folder. I created my report named ReportViolation
,
Now here's the code behind in NewReportViolationWindow
.
ReportDocument reportDocument = new ReportDocument();
string ats = new DirectoryInfo(Environment.CurrentDirectory).Parent.Parent.FullName;
StreamReader reader = new StreamReader(new FileStream(ats.ToString() + @"\Template\ReportViolation.xaml", FileMode.Open, FileAccess.Read));
reportDocument.XamlData = reader.ReadToEnd();
reportDocument.XamlImagePath = Path.Combine(ats.ToString(), @"Template\");
reader.Close();
DateTime dateTimeStart = DateTime.Now; // start time measure here
List<ReportData> listData = new List<ReportData>();
//foreach (string item in GlobalVar.ViolationRefNumToPrint)
for (int i = 0; i < 5 ; i++)
{
ReportData data = new ReportData();
data.ReportDocumentValues.Add("PrintDate", DateTime.Now);
data.ReportDocumentValues.Add("EmpIDNum", NewIDNumber.ToString());
data.ReportDocumentValues.Add("EmpName", NewEmpName.ToString());
data.ReportDocumentValues.Add("EmpPosition", NewPosition.ToString());
//data.ReportDocumentValues.Add("VioRefCode", item.ToString());
listData.Add(data);
}
XpsDocument xps = reportDocument.CreateXpsDocument(listData);
documentViewer.Document = xps.GetFixedDocumentSequence();
// show the elapsed time in window title
Title += " - generated in " + (DateTime.Now - dateTimeStart).TotalMilliseconds + "ms";
}
catch (Exception ex)
{
// show exception
MessageBox.Show(ex.Message + "\r\n\r\n" + ex.GetType() + "\r\n" + ex.StackTrace, ex.GetType().ToString(), MessageBoxButton.OK, MessageBoxImage.Stop);
}
Now when i run my application and click the print button. Sometimes at first it will open the NewReportViolationWindow
with no error but when i try to close the report or click the button again, it will give a message,
Specified Visual is already a child of another Visual or the root of the component target
Here's an image of the error,
I think the problem is when i call the print report which the code behind the print button, hmmm can anyone? pls... :)
2ND EDIT
About your question:
Yes correct..
ReportViolationWindow
?Sorry I don't have any idea coz what i did is i just followed the sample in the Open Source.
ReportViolationWindow
?So far i still don't have a code for proper closing of my ReportViolationWindow
. When i click the close button and that's it, sorry for that. :(
ReportViolationWindow
instance?No. as far as i know.
Upvotes: 2
Views: 6105
Reputation: 9
Ok, I might have a solution. If I change that second code snippet above to
Code Block
ContainerVisual smallerPage = new ContainerVisual( );
DrawingVisual pageVisual = page.Visual as DrawingVisual;
if ( pageVisual != null && pageVisual.Parent != null )
{
ContainerVisual parent = pageVisual.Parent as ContainerVisual;
parent.Children.Remove( pageVisual );
}
smallerPage.Children.Add( page.Visual );
It seems to work. Please comment. I would LOVE to know if there is a better way. This seems like a hack.
Upvotes: 1
Reputation: 16894
You have to "detach" a Visual from it's current Parent before you can add it to a new Parent - the reason for this is primarily due to the way the rendering and composition engine works; if the original parent element did not know it wasn't in charge of rendering that child anymore, and WPF allowed you to attach it to another parent, in the best case scenario, you'd have duplicate Visuals rendered, and in a worst case scenario, you could end up in an infinite loop!
Since the responsibility is on the Parent element to add/remove children, you would need to handle this at the parent level, generally with either a call to RemoveLogicalChild
or RemoveVisualChild
(or ideally, removing the item itself from the original ItemsSource and adding it to the new one)
EDIT: technically, the first paragraph is true, but I don't think the second applies to you...after looking through the source code for the ReportPaginator
class at WpfReports on CodePlex, I noticed the following:
Now, to your actual problem:
You say that the report window usually opens up without an error the first time, but not after that?
Are there any shared resources that are being used in the ReportViolationWindow
?
How are you disposing of/handling the close of the ReportViolationWindow
?
Are you keeping any other references to this ReportViolationWindow
instance?
One thing I would try, just to see if the error continues, is to declare a single member variable of type NewReportViolationWindow
in the window that is creating it (EmployeeProfileWindow
), and instead of this:
private void btnprintviolation_Click(object sender, RoutedEventArgs e)
{
ReportViolationWindow NewReportViolationWindow = new ReportViolationWindow();
Try something like:
ReportViolationWindow _reportViolationWindow;
private void btnprintviolation_Click(object sender, RoutedEventArgs e)
{
if(_reportViolationWindow != null)
{
_reportViolationWindow.Close();
_reportViolationWindow = null;
}
_reportViolationWindow = new ReportViolationWindow();
Upvotes: 1