当我打印控件时,它不显示视图模型中的数据



我正在尝试使用以下代码打印用户控件:

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结构(。

  1. 尽量不要在构造函数中的类之外调用。如您所见,您不能等待构造函数。这是设计使然,因为从某种意义上说,构造函数可以位于不同的线程上。因此,在您的示例中,如果调用以获取数据,则线程的上下文可能与回调不同。如果发生这种情况,您的数据或方法可能会导致错误。

  2. 您正在为后台线程(使用 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();
}

最新更新