我正在尝试使用以下代码打印用户控件:
myUserControlView myView = new myUserControlView();
myUserControlViewModel myViewModel = new myUserControlViewModel(paramItemWithData);
myView.DataContext = myViewModel;
int myFactor;
myFactor = 6;
myView.Measure(new Size(794 * 1, 1122 * 1));
myView.Arrange(new Rect(new Size(794 * 1, 1122 * 1)));
myView.UpdateLayout();
System.Windows.Media.Imaging.RenderTargetBitmap rtb = new System.Windows.Media.Imaging
.RenderTargetBitmap(794 * myFactor, 1122 * myFactor, 96 * myFactor, 96 * myFactor, System.Windows.Media.PixelFormats.Pbgra32);
rtb.Render(myView);
System.Windows.Media.Imaging.PngBitmapEncoder encoder = new System.Windows.Media.Imaging.PngBitmapEncoder();
System.IO.MemoryStream ms = new System.IO.MemoryStream();
encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(rtb));
encoder.Save(ms);
System.Drawing.Image img = System.Drawing.Image.FromStream(ms);
e.Graphics.DrawImage(img, new System.Drawing.PointF());
视图只有一个数据网格,ItemsSource在视图模型中是适当的。当我打印时,结果是我可以看到数据网格的标题,但是它没有行。
我想这是关于刷新视图以从视图模型获取数据的事情,因为视图模型可以正确地从数据库获取数据,但是它不会显示在打印文档中。
谢谢。
编辑:
我注意到问题是当方法异步时,我从数据库中获取数据。如果不是asyc,则可以正常工作。
所以我将分享我的mie模型代码:
public MyViewModel()
{
Task.Run(() => getDataAsync().ConfigureAwait(false));
}
private ObservableCollection<MyType> _myItems = new ObservableCollection<MyType>();
public ObservableCollection<MyType> MyItems
{
get { return _myItems; }
set
{
_myItems = value;
base.RaisePropertyChangedEvent("MyItems");
}
}
private async Task getDataAsync()
{
using(ContextEfCore myDbContext = new ContextEfCore(_optionsDbContext))
{
MyItems = new ObservableCollection<MyType>(await myDbCOntext.MyType.ToListAsync());
}
}
private void getData()
{
using(ContextEfCore myDbContext = new ContextEfCore(_optionsDbContext))
{
MyItems = new ObservableCollection<MyType>(await myDbCOntext.MyType.ToList());
}
}
如果我使用async方法,则不会显示行,但是如果我使用非异步方法,则它将按预期工作。
那么我该如何使用异步方法按预期工作呢?我想避免使用该方法的两个版本,而只希望使用async方法。
谢谢。
答案 0 :(得分:1)
打破MVVM结构的几件事(我认为您正在使用MVVM结构)。
尝试不要在构造函数中的类外部调用。如您所见,您不能等待构造函数。这是设计使然,因为从某种意义上说,构造函数可以位于不同的线程上。因此,在您的示例中,如果调用获取数据,则线程的上下文可能与回调不同。如果发生这种情况,您的数据或方法可能会导致错误。
您正在为后台线程(使用Task.Run()或Task.Start())使用Task结构,而不是I / O线程。由于获取数据是受I / O约束的任务,而getDataAsync是受IO约束的,您可以等待该方法。
异步执行此操作的一个好方法是公开一个在创建视图后触发的方法。 MVVM允许视图了解视图模型。
我的建议是公开getDataAsync方法,或者创建一个诸如PrepareViewModel的新方法,然后在视图中调用它,如果有的话,在导航总线中调用它。
这是将其编码为事件处理程序的方式。
视图模型:
public class MyViewModel
{
public async Task PrepareViewModelAsync()
{
await getDataAsync();
// add other code to prepare the view model.
// ...
}
private async Task getDataAsync()
{
using(ContextEfCore myDbContext = new ContextEfCore(_optionsDbContext))
{
MyItems = new ObservableCollection<MyType>(await myDbCOntext.MyType.ToListAsync());
}
}
}
视图(Xaml)添加一个已加载的事件:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded">
<Grid>
</Grid>
</Window>
后面的视图代码,定义事件处理程序:
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
// get the view model from the data context
var viewModel = DataContext as MyViewModel;
if (viewModel != null) await viewModel.PrepareViewModelAsync();
}