朋友! 有一个主窗口,它包含一个框架,我可以在其中切换页面。 我有一个带有画布的页面。后台流中的画布在镶嵌视图中以图像形式接收数据。
foreach (var item in CoreData.fillWallArray.GetConsumingEnumerable())
{
if (File.Exists(item.PathFile))
{
Application.Current.Dispatcher.Invoke(new Action(() =>
{
Image image = new Image();
image.Source = BitmapImageFromFile(item.PathFile);
image.Width = (int)Math.Truncate((CoreData.settings.CellWidth * 30) / 2.54);
image.Height = (int)Math.Truncate((CoreData.settings.CellHeight * 30) / 2.54);
Canvas.SetLeft(image, item.Column * (int)Math.Truncate((CoreData.settings.CellWidth * 30) / 2.54));
Canvas.SetTop(image, item.Row * (int)Math.Truncate((CoreData.settings.CellHeight * 30) / 2.54));
can.Children.Add(image);
}));
Thread.Sleep(100);
}
}
我的任务是将此画布带到第二个屏幕。为此,我创建了第二个窗口,并作为上下文传递所需的画布。
var _BroadcastWindow = new BroadcastWindow();
_BroadcastWindow.DataContext = this.can;
_BroadcastWindow.Show();
在第二个窗口中,我链接数据。
<Grid>
<Grid.Background>
<VisualBrush Visual="{Binding}"/>
</Grid.Background>
</Grid>
一切正常,画布中的数据同步显示在第二个窗口中。但是,一旦我切换到另一个页面,Visualbrush将不再更新。当我切换回在第二个窗口中看到的带有画布的页面时,它就会被更新。 可能是什么问题呢? 当在后台线程中向画布中添加数据时,我也尝试调用Measure,Arrange,UpdateLayout,但这没有产生结果。
答案 0 :(得分:1)
我假设当您说“转到另一页”时,您的意思是:
frame.Navigate(new System.Uri("Page2.xaml", UriKind.RelativeOrAbsolute));
每次执行此操作时,您的应用都会从给定的来源中加载新的Page
。如果当前页面恰好是上面有您的Page
的{{1}},则导航将创建一个新的Canvas
实例。如果不是,并且Canvas
中没有为Page
设置JournalEntry.KeepAlive="true",则Canvas
的内容只会从每个Frame
文件中重新创建时间显示出来,并随之创建一个新的Source
。在某些时候,某些东西会断开连接或被过早破坏。即使将Canvas
设置为KeepAlive
,您也可能最终会在内存中加载True
的多个实例。您想绑定到哪一个...?
有些另类的方法使我无法自拔:
将Canvas
本身缓存在您的视图模型中,并将Image
上的Canvas
和Page
都绑定到此。
在视图模型中缓存整个VisualBrush
,然后根据需要切换其内容。
第二种方法只需要对代码进行最少的更改,因此我可以举一个可行的示例(尽管我不知道它是否是最佳的):
在Canvas
(显示“画布”的页面)中:
Page1.xaml
在<Grid>
<ContentControl Content="{Binding canvas, Source={x:Static local:CanvasViewModel.Instance}}" />
</Grid>
中:
BroadcastWindow.xaml
用于容纳画布的单例视图模型示例:
<Grid>
<Grid.Background>
<VisualBrush Visual="{Binding}"/>
</Grid.Background>
</Grid>
在帧外的public class CanvasViewModel
{
Rectangle r = new Rectangle
{
Fill = Brushes.Orange,
Width = 200,
Height = 100
};
Ellipse e = new Ellipse
{
Fill = Brushes.DodgerBlue,
Width = 100,
Height = 100
};
public Canvas canvas { get; set; }
public void Initialize()
{
canvas = new Canvas();
Switch(1);
}
// Here the contents of the canvas are switched
// I called it from Click events of two Buttons outside of Frame
// In your case, I imagine it will be something like this:
// public void LoadImage(string path) {...}
public void Switch(int imageNr)
{
switch (imageNr)
{
case 1:
canvas.Children.Clear();
canvas.Children.Add(r);
break;
case 2:
{
canvas.Children.Clear();
canvas.Children.Add(e);
}
break;
default:
break;
}
}
#region CONSTRUCTOR
static CanvasViewModel() { }
private CanvasViewModel() { }
private static CanvasViewModel GetAppViewModelHolder()
{
CanvasViewModel vh = new CanvasViewModel();
vh.Initialize();
return vh;
}
#endregion
#region SINGLETON Instance
private static readonly object _syncRoot = new object();
private static volatile CanvasViewModel instance;
public static CanvasViewModel Instance
{
get
{
var result = instance;
if (result == null)
{
lock (_syncRoot)
{
if (instance == null)
{
result = instance = GetAppViewModelHolder();
}
}
}
return result;
}
}
#endregion
}
的{{1}}事件中的图像之间切换:
Click