我正在尝试使用以下代码打印用户控件:
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());
}
}
如果我使用异步方法,它不会显示行,但如果我使用非异步方法,它会按预期工作。
那么如何使用异步方法按预期工作呢?我想避免使用该方法的两个版本,我只想使用异步方法。
谢谢。
破坏MVVM结构的几件事(我认为您正在使用MVVM结构(。
-
尽量不要在构造函数中的类之外调用。如您所见,您不能等待构造函数。这是设计使然,因为从某种意义上说,构造函数可以位于不同的线程上。因此,在您的示例中,如果调用以获取数据,则线程的上下文可能与回调不同。如果发生这种情况,您的数据或方法可能会导致错误。
-
您正在为后台线程(使用 Task.Run(( 或 Task.Start(((而不是 I/O 线程使用 Task 结构。由于获取数据是 I/O 绑定任务,而 getDataAsync 是 IO 绑定的,因此您可以等待该方法。
异步执行此操作的一个好方法是公开在创建视图后触发的方法。MVVM 允许视图了解视图模型。
我的建议是公开getDataAsync Method,或者创建一个像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();
}