关于如何替换WPF中显示的UserControl,我已经阅读了很多关于此事的主题。 建议倾向于数据绑定内容控制,Kent Boggart回答this question。
无论如何,第一个问题是我的用户控件涉及繁重的图形显示,并且正在使用不能同时访问的公共资源。
我的意思是重型图形,在OtherControl
上,有几个视频和一个3D模型,对动态事件作出反应。 BallControl
有一个带有TranslateAnimation的椭圆,以及一个对事件做出反应的边距。我相信由于渲染页面的动态事件,整个项目有点沉重。
所以我的解决方案并不理想:我正在清除Grid
中的内容,并将其替换为所需的用户控件(网格占据整个页面)。
与上述帖子的不同之处在于,我希望(如果可能的话)保持用户控制不变。
问题在于,这些控件需要经常切换,并且在 1或2小时后使用它时,此异常显示(代码中指定的行):
System.ArgumentException:指定的Visual已经是另一个Visual的子项或CompositionTarget类的根。
System.Windows.Threading.Dispatcher.Invoke(Action callback,DispatcherPriority priority,CancellationToken cancellationToken,TimeSpan timeout)
我的代码显然是错误的,我希望有一个更清洁的解决方案。更重要的是,我已经知道只有一个UI线程,并且预先加载已经构建的控件,然后才能进行二次拉伸。 更确切地说,一些代码非常受欢迎:
MainWindow.xaml :
<Window x:Class="Testing.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Testing"
xmlns:h="http://helix-toolkit.org/wpf"
Title="MainWindow" Height="1080" Width="1920" WindowStartupLocation="CenterScreen" WindowStyle="None" MinHeight="1080" MinWidth="1920" ResizeMode="NoResize">
<Grid x:Name="Griddy">
</Grid>
MainWindow.xaml.cs :
BallControl _boule;
OtherControl _otherControl;
public MainWindow()
{
InitializeComponent();
Mouse.OverrideCursor = Cursors.None;
EventReceive.Subscribe(this);
// Instanciate both UserControls
_boule = new BallControl();
_otherControl = new OtherControl();
panelToDisplay = Turn.Ball;
Griddy.Children.Add(boule);
}
/// <summary>
/// Event coming from panels to notify which one is to be displayed
/// returning value is an Enum
/// </summary>
public void Receive<T>(T arg) where T : EventArgs
{
var casted = arg as EventArriving;
if (casted != null)
{
PanelToDisplay = casted.TurningTable;
}
}
private Turn panelToDisplay;
public Turn PanelToDisplay
{
get { return panelToDisplay; }
set
{
if (panelToDisplay != value)
{
panelToDisplay = value;
if (panelToDisplay == Turn.Other)
{
try
{
this.Griddy.Dispatcher.Invoke((Action)(() => Griddy.Children.Add(_otherControl))); //Where the exception shows up
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
try
{
this.Griddy.Dispatcher.Invoke((Action)(() => Griddy.Children.Remove(_boule)));
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
if (panelToDisplay == Turn.Ball)
{ // Bad Pattern where I remove a control to display another one.
try
{
this.Griddy.Dispatcher.Invoke((Action)(() => Griddy.Children.Add(_boule))); //Where the exception shows up
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
try
{
this.Griddy.Dispatcher.Invoke((Action)(() => Griddy.Children.Remove(_otherControl)));
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
}
}
}
总结一下: