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

时间:2018-06-23 09:16:40

标签: wpf mvvm printing

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

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方法。

谢谢。

1 个答案:

答案 0 :(得分:1)

打破MVVM结构的几件事(我认为您正在使用MVVM结构)。

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

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