Offline binding

Is there any means to initialize "offline" binding for elements I've created in code through .baml/xaml parsing or imperative
What if I've <ViewBox/> with some resources+binded elements-all self contained but I created it from "sratch" and it's not displayed on screen.Now I want to simulate "complete" cycle of rendering to get RenderTargetBitmap of my ViewBox...well you get idea
All work nice except {Binding} markup expressions dosen't get called.So,how I can "invoke" expression engine to make binding work.
I tried:
vb.Measure(new Size(1000,1000));
vb.Arrange(new Rect(vb.DesiredSize));
vb.UpdateLayout();

without luck from console app,have I forgot something

Thanks.



Answer this question

Offline binding

  • doakwolf

    OK, we have:

    <graph1 project>

    Window1.xaml.cs:

    namespace graph1 {

    /// <summary>

    /// Interaction logic for Window1.xaml

    /// </summary>

    public partial class Window1:Window {

    ///...

    public void RenderBitmap() {

    vb.Measure(new Size(1000, 1000));

    vb.Arrange(new Rect(vb.DesiredSize));

    vb.UpdateLayout();

    RenderTargetBitmap rtb = new RenderTargetBitmap(Convert.ToInt32(vb.DesiredSize.Width), Convert.ToInt32(vb.DesiredSize.Height), 0, 0, new PixelFormat());

    rtb.Render(vb);

    JpegBitmapEncoder png = new JpegBitmapEncoder();

    png.Frames.Add(BitmapFrame.Create(rtb));

    using (FileStream fs = new FileStream("aaa.jpg", FileMode.Create)) {

    png.Save(fs);

    }

    }

    ///…

    public class MyConverter : IValueConverter, IMultiValueConverter

    {

    public object Convert(

    object o,

    Type type,

    object parameter,

    System.Globalization.CultureInfo culture) {

    if (type == typeof(PointCollection)) {

    PointCollection pc = new PointCollection();

    XmlElement el = (XmlElement)o;

    XmlElement doc = el.OwnerDocument.DocumentElement;

    double y_max = double.Parse(doc.GetAttribute("Y_MAX")),

    x_step = 1.75 * y_max / double.Parse(doc.GetAttribute("X_MAX"));

    pc.Add(new Point(0, y_max));

    foreach (XmlElement p in el.SelectNodes("Point")) {

    Debug.WriteLine(p.GetAttribute("XX") + " " + p.GetAttribute("YY"));

    Point pv = new Point(double.Parse(p.GetAttribute("XX")) * x_step, y_max - double.Parse(p.GetAttribute("YY")));

    pc.Add(pv);

    }

    return pc;

    }

    else {

    if (o is XmlAttribute) {

    XmlAttribute a = (XmlAttribute)o;

    double _max = double.Parse(a.OwnerElement.Attributes["Y_MAX"].Value);

    if (a.Name == "X_MAX") _max = 1.75 * _max;

    return _max;

    }

    else {

    return 38492520.04 / 100;

    }

    }

    }

    public object ConvertBack(object o, Type type,object parameter,System.Globalization.CultureInfo culture) {

    throw new NotImplementedException();

    }

    #region IMultiValueConverter Members

    public object Convert(object[] values, Type targetType,object parameter,System.Globalization.CultureInfo culture) {

    double[] w = Array.ConvertAll<object, double>(values, delegate(object o) { return 0.1; });

    return 100000d;

    }

    public object[] ConvertBack(object value, Type[] targetTypes,object parameter,System.Globalization.CultureInfo culture) {

    throw new NotImplementedException();

    }

    #endregion

    }

    }

    Window1.xaml:

    <Window x:Class="graph1.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:c="clr-namespace:graph1"

    Title="graph1" Loaded="hh">

    <Window.Resources>

    <Style x:Key="Title" TargetType="{x:Type TextBlock}">

    <Setter Property="FontSize" Value="22"/>

    </Style>

    </Window.Resources>

    <StackPanel>

    <Viewbox x:Name="vb">

    <Viewbox.Resources>

    <c:MyConverter x:Key="l_c"/>

    <XmlDataProvider x:Key="line" XPath="doc">

    <x:XData>

    <doc xmlns="" Y_MAX="38492520.04" X_MAX="10">

    <Line NAME="aaa" COLOR="Blue">

    <Point X_VALUE="26.09.05" XX="1" YY="15421199.2"/>

    <Point X_VALUE="27.09.05" XX="2" YY="15730949.79"/>

    </Line>

    <Line NAME="bbb" COLOR="Red">

    <Point X_VALUE="26.09.05" XX="1" YY="349889.81"/>

    <Point X_VALUE="27.09.05" XX="2" YY="1557119.47"/>

    </Line>

    </doc>

    </x:XData>

    </XmlDataProvider>

    <DataTemplate x:Key="LineG">

    <Polyline

    Stroke="{Binding XPath=@COLOR}"

    StrokeThickness="100000"

    Points="{Binding Mode=OneTime,Converter={StaticResource l_c}}"/>

    </DataTemplate>

    </Viewbox.Resources>

    <Grid Background="White">

    <Grid.RowDefinitions>

    <RowDefinition/>

    <RowDefinition/>

    </Grid.RowDefinitions>

    <Grid.ColumnDefinitions>

    <ColumnDefinition Width="Auto"/>

    <ColumnDefinition Width="*"/>

    </Grid.ColumnDefinitions>

    <Grid.Resources>

    <Style TargetType="{x:Type StackPanel}">

    <Setter Property="LayoutTransform">

    <Setter.Value>

    <ScaleTransform ScaleX="100000" ScaleY="100000"/>

    </Setter.Value>

    </Setter>

    </Style>

    </Grid.Resources>

    <StackPanel VerticalAlignment="Bottom">

    <StackPanel.Resources>

    <Style TargetType="{x:Type TextBlock}">

    <Setter Property="Margin" Value="0,100,0,0"/>

    </Style>

    </StackPanel.Resources>

    <TextBlock>aaaaaaaaaaa</TextBlock>

    <TextBlock>aaaaaaaaaaa</TextBlock>

    <TextBlock>aaaaaaaaaaa</TextBlock>

    </StackPanel>

    <Border Grid.Column="1"

    BorderBrush="Green"

    DataContext="{StaticResource line}"

    BorderThickness="100000,0,0,100000">

    <ItemsControl x:Name="zz1" ItemsSource="{Binding XPath=*}" ItemTemplate="{StaticResource LineG}">

    <ItemsControl.Template>

    <ControlTemplate TargetType="{x:Type ItemsControl}">

    <Canvas

    IsItemsHost="True"

    Width="{Binding Path=Attributes[X_MAX],Mode=OneTime,Converter={StaticResource l_c}}"

    Height="{Binding Path=Attributes[Y_MAX],Mode=OneTime,Converter={StaticResource l_c}}"/>

    </ControlTemplate>

    </ItemsControl.Template>

    </ItemsControl>

    </Border>

    <StackPanel Grid.Column="1" Grid.Row="1"

    HorizontalAlignment="Left"

    Orientation="Horizontal">

    <StackPanel.Resources>

    <Style TargetType="{x:Type TextBlock}">

    <Setter Property="LayoutTransform">

    <Setter.Value>

    <RotateTransform Angle="45"/>

    </Setter.Value>

    </Setter>

    </Style>

    </StackPanel.Resources>

    <TextBlock>aaaaaaaaaaa1</TextBlock>

    <TextBlock>aaaaaaaaaaa2</TextBlock>

    <TextBlock>aaaaaaaaaaa3</TextBlock>

    </StackPanel>

    </Grid>

    </Viewbox>

    </StackPanel>

    </Window>

    //================================================================================

    Next,put following files in “debug” output directory of this project(workaround for .baml loading-to simulate window loading cycle):

    a.cs:

    using System.Windows;

    using System;

    class a

    {

    [System.STAThreadAttribute]

    static void Main() {

    graph1.Window1 w = new graph1.Window1();

    w.RenderBitmap(true);//this will render “aaa.jpg”

    System.Console.ReadLine();

    }

    }

    a.cmd:

    copy %PATH_TO_GRAPH1_PROJECT%\obj\Debug\graph1.g.resources a.g.resources

    csc /res:a.g.resources /r:PresentationFramework.dll,PresentationCore.dll,WindowsBase.dll,UIAutomationProvider.dll,graph1.exe a.cs

    //=======================================

    and run a.cmd(after building graph1;-),you’ll get a.exe-console application that creates Window1 object and execute RenderBitmap method.Ofcourse,you can run graph1 project itself and see the difference(just add Loaded handler,for example which invoke RenderBitmap).

    That’s all.

    Run a.exe,in result we have “aaa.jpg” without binding…

    Thank you.

    P.S. By the way,"Loaded" for ViewBox or Window is never called in "offline/cosole" mode but it render static content anyway though binding engine is not working.Who responsible to raise "Loaded" event


  • mh433493

    Look at previous post-it's simple console app,I tried:

    graph1.Window1 w= new graph1.Window1();

    w.Dispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(

    delegate(object o)

    {

    w.RenderBitmap(true);

    return null;

    }

    ));

    as you suggest-no luck,app just wait indefinitely.

    Thanks.


  • Carlos Guzm&amp;#225;n &amp;#193;lvarez

    I'm not 100% sure, but my gut tells me what you're trying to do isn't possible with WPF.

    I'll need to find an expert on this, though.



  • Raptor0001

    Could you give me a bit more context.

    You're creating a ViewBox in code How are you adding it to the tree What is it's parent



  • SteveS_MS

    Ah, you need an Application running.

    No Application, no dispatcher...at least I'm pretty sure. (Need to chat with the experts...)

    Regardless, I'm pretty sure you won't get an Image for the Window if you don't show the Window...otherwise Measure/Arrange/Render won't be called.



  • Joe Brinkman

    Could you show your full code with and without binding That'll help us figure this out...

  • TimSpencer

    I'm not adding it to the tree and application event pulling cycle is not started-Application.Run(); is never invoked,so dispatcher thread is out of work;-)
    All I do is deserialize ViewBox object from .xaml file using parser and tried to render it to .jpg using supplied code(no parent here)-it's simple console application,hence term "offline".

    Thanks.


  • Martha Wieczorek

    What code calls "RenderBitmap"

    You may need to do a Dispatcher.BeginInvoke at Background priority to allow all of the bindings to update before you try to capture the image.

    Have you used the dispatcher before



  • chrisexv6

    So,what you think I've missed something

    Best wishes.


  • ronnotel

    I can assure you that ViewBox(background image,coordinate lines-static XAML content,I can call Measure/Arrange methods manually,but I can't call Bind() as in asp.net) rendered perfectly well,but all dynamic functionality is turned off.I agree Application may be required but how I can do Application.Run()-start message processing cycle in non interactive environment-that's the question(for example in asp.net context or console app).

    Thanks.


  • Bhargavi

    I'm confused. Where are you defining the Binding In code In xaml

  • pant

    As I can understand,it dosen't matter where,if you have {} expressions or "Binding" objects itself.
    I tried:
    vb.Measure(new Size(1000,1000));
    vb.Arrange(new Rect(vb.DesiredSize));
    vb.UpdateLayout();
    RenderTargetBitmap rtb=new RenderTargetBitmap(Convert.ToInt32(vb.DesiredSize.Width),Convert.ToInt32(vb.DesiredSize.Height),0,0,new PixelFormat());
    rtb.Render(vb);// this dosen't respect {Binding} for Height and other properties

    //binding simply not work IF vb (ViewBox) is created offline-is not displayed on screen(not inserted in visual tree),but created in imperative code(or loaded from .xaml file,it dosen't matter)


    JpegBitmapEncoder png=new JpegBitmapEncoder();
    png.Frames.Add(BitmapFrame.Create(rtb));
    using(FileStream fs=new FileStream("aaa.jpg",FileMode.Create)) {
    png.Save(fs);
    }

    because of that "aaa.jpg" is empty-most of the logical tree of vb binded to some datasource(defined in vb context),particularly measurement properties of objects.So,you have nothing if you not displaying it on screen.

    Regards.


  • drajurs

    OK,I'll prepare code and put it here.

    Thank you.


  • ralphg

    Maybe some kind of mini bootstrap for Avalon subsystem exist without dispatcher participation By the way,if you're not using any expressions(binding included)-only pure static file(all props predefined in tree),all work as expected.

    Regards.


  • Offline binding