wpf 指定的 Visual 已经是另一个 Visual 的子项或组件目标的根

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13426227/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 06:15:34  来源:igfitidea点击:

Specified Visual is already a child of another Visual or the root of the component target

c#wpf

提问by Kenshi Hemura

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 linkand use it. So i tried to use it, pls check my code,

嗨,伙计们,我一直在使用 WPF C# 搜索报告,并找到了一份不错的报告,而且也很简单,找到了这个链接并使用它。所以我尝试使用它,请检查我的代码,

in my EmployeeProfileWindowin print button,

在我EmployeeProfileWindow的打印按钮中,

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,

所以如果我点击按钮,它会出现一个新的窗口名称NewReportViolationWindow。我将在模板文件夹中复制或编辑开源示例中的内容。我创建了名为 的报告ReportViolation

Now here's the code behind in NewReportViolationWindow.

现在这里是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 NewReportViolationWindowwith no error but when i try to close the report or click the button again, it will give a message,

现在,当我运行我的应用程序并单击打印按钮时。有时一开始它会打开NewReportViolationWindow没有错误但是当我尝试关闭报告或再次单击按钮时,它会给出一条消息,

Specified Visual is already a child of another Visual or the root of the component target

指定的 Visual 已经是另一个 Visual 的子项或组件目标的根

Here's an image of the error,

这是错误的图像,

enter image description here

在此处输入图片说明

I think the problem is when i call the print report which the code behind the print button, hmmm can anyone? pls... :)

我认为问题是当我调用打印按钮背后的代码的打印报告时,嗯,任何人都可以吗?请... :)

2ND EDIT

第二次编辑

关于你的问题:

  • You say that the report window usually opens up without an error the first time, but not after that?
  • 您说报告窗口通常在第一次打开时没有错误,但之后就没有了?

Yes correct..

是,对的..

  • Are there any shared resources that are being used in the ReportViolationWindow?
  • 中是否有正在使用的共享资源 ReportViolationWindow

Sorry I don't have any idea coz what i did is i just followed the sample in the Open Source.

抱歉,我不知道因为我所做的是我只是按照开源中的示例进行操作。

  • How are you disposing of/handling the close of the ReportViolationWindow?
  • 您如何处置/处理 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. 当我点击关闭按钮时,就是这样,抱歉。:(

  • Are you keeping any other references to this ReportViolationWindowinstance?
  • 您是否保留对此ReportViolationWindow实例的任何其他引用?

No. as far as i know.

不,据我所知。

回答by JerKimball

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!

在将它添加到新的父级之前,您必须从它的当前父级中“分离”一个 Visual - 其原因主要是由于渲染和合成引擎的工作方式;如果原始父元素不知道它不再负责渲染该子元素,并且 WPF 允许您将其附加到另一个父元素,在最好的情况下,您将渲染重复的视觉效果,在最坏的情况下场景,你可能会陷入无限循环!

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 RemoveLogicalChildor RemoveVisualChild(or ideally, removing the item itself from the original ItemsSource and adding it to the new one)

由于添加/删除子元素的责任在 Parent 元素上,因此您需要在父级处理此问题,通常调用RemoveLogicalChildor RemoveVisualChild(或理想情况下,从原始 ItemsSource 中删除项目本身并将其添加到新的一)

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 ReportPaginatorclass at WpfReports on CodePlex, I noticed the following:

编辑:从技术上讲,第一段是正确的,但我认为第二段不适用于你......ReportPaginator浏览了 CodePlexWpfReports类的源代码后,我注意到以下几点:

  • The latest version is different from yours, I believe: the line #'s don't quite match up. Possibly this is a bug that has been fixed?
  • (Nitpicky) I am not a fan of the structure of this code (the report engine that is)...ArrayLists? Single line if/else/return statements? ugh
  • 最新版本与您的不同,我相信:# 行不太匹配。可能这是一个已修复的错误?
  • (挑剔)我不喜欢这段代码的结构(报表引擎)...ArrayLists?单行 if/else/return 语句?

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 anyother references to this ReportViolationWindowinstance?

  • 您说报告窗口通常在第一次打开时没有错误,但之后就没有了?

  • 中是否有正在使用的共享资源ReportViolationWindow

  • 您如何处置/处理ReportViolationWindow?

  • 您是否保留对此实例的任何其他引用ReportViolationWindow

One thing I would try, just to see if the error continues, is to declare a single member variable of type NewReportViolationWindowin the window that is creating it (EmployeeProfileWindow), and instead of this:

我会尝试的一件事,只是为了看看错误是否继续,是NewReportViolationWindow在创建它的窗口中声明一个类型的成员变量( EmployeeProfileWindow),而不是这样:

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();

回答by Farhad Karbasian

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.

它似乎工作。请给出意见。我很想知道是否有更好的方法。这似乎是一个黑客。