如何在System.Windows.Application之外执行DataBinding

时间:2011-03-23 12:43:38

标签: .net wpf image-processing binding

所以这是senerio。

我想建立一个图像库,其中包含来自数据库图像的文本。

我试图通过使用template.xaml文件并在ClassLibrary项目中实例化它来实现此目的。因此,xaml文件正在WPF应用程序范围之外实例化。

我正在尝试创建一个类似于此链接中所解释的PivotCollection

http://martimedia.blogspot.com/2010/07/creating-pivot-collection.html

我最终继承了我的类库中的System.Windows.Application以使其工作,但这远非理想,因为它引发了有关所使用的AppDomain的问题。

我编写了一些简单的示例代码来简单地展示我想要实现的目标。

这是一个我想要绑定的简单POCO。

public class DataObject {
   public DataObject(string value) {
      Property = value;
   }
   public string Property { get; set; }
}

这是一个我想要绑定的简单“图像模板”。

<UserControl x:Class="XamlRenderingExample.Template"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
   xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
   mc:Ignorable="d" 
   d:DesignHeight="300" d:DesignWidth="300">
  <Grid>
    <TextBlock Text="{Binding Property}"></TextBlock>
  </Grid>
</UserControl>

这是一个简单的类库,用于从xaml

创建图像
public class CreateBitmapImagesFromXamlTemplate {
  public CreateBitmapImagesFromXamlTemplate() {
     Template template = new Template();
     foreach (DataObject obj in GetDataObjects())
     {
        template.DataContext = obj;
        RenderXamlAsBitMap(template); 
     }
  }

  private void RenderXamlAsBitMap(Template template) {
     template.Arrange(new Rect(0, 0, 300, 300));
     RenderTargetBitmap bitmap = new RenderTargetBitmap((int)template.RenderSize.Width,
                       (int)template.RenderSize.Height,
                        96,
                        96, PixelFormats.Default);
     bitmap.Render(template);
     // Save away the bitmap to file.
  }

  private static List<DataObject> GetDataObjects() {
     return new List<DataObject>()
     {
        new DataObject("Hello"),
        new DataObject("Another string")
     };
  }
}

问题在于,如果不将Xaml添加到WPF应用程序设置中的渲染窗口,则datacontext将不会执行所需的绑定,结果是textBlock将不会显示DataObject中的数据。

据我所知,如果我们在WPF应用程序中并且在设置模板的dataContext时将模板添加到渲染窗口,则在Dispatcher中对作业进行qued以实际执行数据绑定并从DataObject中提取值到模板。

我想要做的是能够在我的类库中手动执行此例程,而无需实例化System.Windows.Application对象。

有人有任何想法吗?

1 个答案:

答案 0 :(得分:0)

经过一些进一步的修改并意识到我的第一个解决方案的工作原理并不是将用户控件添加到应用程序对象的可视化树中,而是在Dispatcher上排除作业。

我修改了上面的类来排队现在使用以下代码对保存的图像执行所需的“数据绑定”的作业:

public class CreateBitmapImagesFromXamlTemplate {
    Template template;
    RenderTargetBitmap bitmap;

public CreateBitmapImagesFromXamlTemplate() {
    template = new Template();

    foreach (DataObject obj in GetDataObjects()) {
        RenderXamlAsBitMap(template, obj); 
    }
}

private void RenderXamlAsBitMap(Template template, DataObject dataObject) {
    var renderFrame = new DispatcherFrame(true);
    QueueDataBinding(dataObject, renderFrame);
    QueueRenderBitmap(renderFrame);
    System.Windows.Threading.Dispatcher.PushFrame(renderFrame);  
    SaveRenderedBitmap(bitmap);
}

private static List<DataObject> GetDataObjects() {
    return new List<DataObject>() {
    new DataObject("Hello"),
        new DataObject("Another string")
  };
}

private void SaveRenderedBitmap(RenderTargetBitmap renderedBitmap) {
    var encoder = new JpegBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create(renderedBitmap));
    using (FileStream fs = File.Open(@"C:\temp\imageTesting.jpg", 
        FileMode.OpenOrCreate)) {
            encoder.Save(fs);
        }
    }

    private void QueueDataBinding(DataObject dataObject, 
    DispatcherFrame renderFrame) {
        Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.DataBind, 
            (ThreadStart)delegate() {
            template.DataContext = dataObject;
            renderFrame.Continue = true;
  });
}

private void QueueRenderBitmap(DispatcherFrame renderFrame) {
    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, 
        (ThreadStart)delegate() {
        RenderBitmap();
        renderFrame.Continue = false;
        });
    }

    private void RenderBitmap() {
        template.Arrange(new Rect(0, 0, 300, 300));
        bitmap = new RenderTargetBitmap((int)template.RenderSize.Width,
            (int)template.RenderSize.Height,
            96,
            96, PixelFormats.Default);
        bitmap.Render(template);
        SaveRenderedBitmap(bitmap);
    }
}