Study/WPF - 해당되는 글 4건
저작자 표시
신고

'Study > WPF' 카테고리의 다른 글

[WPF_Program: Window Desktop Interface]  (3) 2011.02.12
[WPF: insert XAML into RichTextBox]  (0) 2010.12.20
[WPF: Diagramming. Saving you canvas to image]  (0) 2010.10.20
[WPF : Data Binding]  (0) 2010.07.28
Trackback 0 | Comments 3

Retrive a XAML text from RichTextBox:

private static string GetRTF(RichTextBox rt)
{
   
TextRange range = new TextRange(rt.Document.ContentStart, rt.Document.ContentEnd);
   
MemoryStream stream = new MemoryStream();
    range
.Save(stream, DataFormats.Xaml);
   
string xamlText = Encoding.UTF8.GetString(stream.ToArray());
   
return xamlText;
}

Render a XAML text into a RichTextBox:

private static FlowDocument SetRTF(string xamlString)
{
   
StringReader stringReader = new StringReader(xamlString);
   
XmlReader xmlReader = XmlReader.Create(stringReader);
   
Section sec = XamlReader.Load(xmlReader) as Section;
   
FlowDocument doc = new FlowDocument();
   
while (sec.Blocks.Count > 0)
        doc
.Blocks.Add(sec.Blocks.FirstBlock);
   
return doc;
}


저작자 표시
신고

'Study > WPF' 카테고리의 다른 글

[WPF_Program: Window Desktop Interface]  (3) 2011.02.12
[WPF: insert XAML into RichTextBox]  (0) 2010.12.20
[WPF: Diagramming. Saving you canvas to image]  (0) 2010.10.20
[WPF : Data Binding]  (0) 2010.07.28
Trackback 0 | Comment 0

Exporting canvas to PNG image

public void ExportToPng(Uri path, Canvas surface)
{
  if (path == null) return;

  // Save current canvas transform
  Transform transform = surface.LayoutTransform;
  // reset current transform (in case it is scaled or rotated)
  surface.LayoutTransform = null;

  // Get the size of canvas
  Size size = new Size(surface.Width, surface.Height);
  // Measure and arrange the surface
  // VERY IMPORTANT
  surface.Measure(size);
  surface.Arrange(new Rect(size));

  // Create a render bitmap and push the surface to it
  RenderTargetBitmap renderBitmap =
    new RenderTargetBitmap(
      (int)size.Width,
      (int)size.Height,
      96d,
      96d,
      PixelFormats.Pbgra32);
  renderBitmap.Render(surface);

  // Create a file stream for saving image
  using (FileStream outStream = new FileStream(path.LocalPath, FileMode.Create))
  {
    // Use png encoder for our data
    PngBitmapEncoder encoder = new PngBitmapEncoder();
    // push the rendered bitmap to it
    encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
    // save the data to the stream
    encoder.Save(outStream);
  }

  // Restore previously saved layout
  surface.LayoutTransform = transform;
}

I’ve again tried to make the code self-explaining. You can try to use different encoders for saving the data so it’s up to you to look through what ones are available. The main trouble many guys come across is blank images as the canvas output or saving canvas programmatically without visualizing it. The key is measuring and arranging the surface before pushing it to render bitmap. As render bitmap does nothing with measuring and arranging elements in this case, this should be regarded mandatory for you. And of course you should remember the zooming/scaling and rotation matrices ;) the layout transformations will also be saved to the image so you should take care of that manually. In my case I cache the LatoutTransform and reset the original value right before measuring canvas.

Paying more attention you can see that bitmap encoder accepts a Visual so canvas is not the only element that can be passed ;) Going down the inheritance tree it is convenient to use the FrameworkElement or pure Visual. FrameworkElement contains Width and Height properties used by canvas.

Default set references provided by WPF application template is quite enough to implement this method. Of course you’ll have to resolve "using" section ;)

Exporting canvas to XPS document

Actually this was the first I’ve started implementing for my application. I like XPS format very much because it is easy to maintain and integrate. Here’s the quick snippet of exporting your canvas to XPS

public void Export(Uri path, Canvas surface)
{
  if (path == null) return;

  // Save current canvas transorm
  Transform transform = surface.LayoutTransform;
  // Temporarily reset the layout transform before saving
  surface.LayoutTransform = null;

  // Get the size of the canvas
  Size size = new Size(surface.Width, surface.Height);
  // Measure and arrange elements
  surface.Measure(size);
  surface.Arrange(new Rect(size));

  // Open new package
  Package package = Package.Open(path.LocalPath, FileMode.Create);
  // Create new xps document based on the package opened
  XpsDocument doc = new XpsDocument(package);
  // Create an instance of XpsDocumentWriter for the document
  XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(doc);
  // Write the canvas (as Visual) to the document
  writer.Write(surface);
  // Close document
  doc.Close();
  // Close package
  package.Close();

  // Restore previously saved layout
  surface.LayoutTransform = transform;
}

You will need two additional assemblies to be referenced from the GAC: "ReachFramework.dll" and "System.Printing.dll". Again I’d advice you to backup the original layout transformation regardless it’s state before processing canvas. You should definitely read more details towards System.IO.Packaging and XPS documents. For those who doesn’t know yet the XPS document is presented by zip container for some xml, fonts and binary data like images etc. You can freely rename XPS to ZIP, unpack it and look inside for better understanding when you’ll be looking though MSDN articles towards it.

I was really pleased to find out that 10 or 20 of my duplicated elements having the same image with content template loaded from the separate assembly wasn’t cloned. I had only one image in the XPS for each distinct type of element so the archive size was extremely small for my diagram.

Exporting canvas to the XAML

I’ll give you the most stupid sample that can be found everywhere

public void Export(Uri path, Canvas surface)
    {
      if (path == null) return;
      if (surface == null) return;

      string xaml = XamlWriter.Save(surface);
      File.WriteAllText(path.LocalPath, xaml);
    }

You get the xaml presentation of your canvas that can be later loaded with XamlReader. Be prepared to cuss MS guys a lot because it is rather difficult to adopt any application load anything except simple xamls into your canvas :) The worst thing is that it doesn’t support bindings/multibindings so you’ll have to resolve them somehow on document loading. The same is for events and there’s a list of things not supported that can be easily found at MSDN shipped with Visual Studio. I’ve looked through the Internet to find any good solution but there’s nothing I liked. Guess if it becomes a hot topic (and I’m sure it will become soon) a lot of good overrides will appear. I’m doing my own implementation but it’s in the early stage and cannot be brought to public.


저작자 표시
신고

'Study > WPF' 카테고리의 다른 글

[WPF_Program: Window Desktop Interface]  (3) 2011.02.12
[WPF: insert XAML into RichTextBox]  (0) 2010.12.20
[WPF: Diagramming. Saving you canvas to image]  (0) 2010.10.20
[WPF : Data Binding]  (0) 2010.07.28
Trackback 0 | Comment 0
데이터 바인딩이란 컨트롤과 엘리먼트를 데이터에 연결시키는 기술이다. 이 정의가 약간 모호할 수있는데, 이것은 데이터 바인딩이 굉장히 넓은 범위와 다양한 기술을 포함하기 때문이다. 데이터 바인딩은  CheckBox 컨트롤을 불리언 변수에 연결하는 것처럼 간단할 수 있고 데이터베이스와 데이터 엔트리 패널을 연결하는 것처럼 복잡해 질 수도 있다.
컨트롤은 데이터를 사용자에게 보여주는 것과 사용자가 데이터를 변경할 수 있게 해주는 2가지 기능을 제공한다.
가장 간단한 바인딩은 2개의 컨트롤 사이에서 존재하는 것이다. 예를 들어 ScrollBar의 Value 프로퍼티를 보여주기 위한 Label 컨트롤을 생각해보자. 이 경우 Scrollbar의 ValueChanged 이벤트 핸들러를 연결하거나 다음의 스탠드얼론 XAML 파일과 같이 데이터 바인딩을 정의할 수 있다.

<Grid>

        <StackPanel VerticalAlignment="Center">

           <ScrollBar Name="scroll" Orientation="Horizontal"

Margin="24" Maximum="100" LargeChange="10"                                       SmallChange="1"/>

            <Label HorizontalAlignment="Center"

Content="{Binding ElementName=scroll, Path=Value}" />

        </StackPanel>

    </Grid>



<Grid>

        <StackPanel VerticalAlignment="Center">

            <ScrollBar Name="scroll" Orientation="Horizontal"

Margin="24" Maximum="100" LargeChange="10"                       SmallChange="1"/>

            <Label HorizontalAlignment="Center">

                <Label.Content>

                    <Binding ElementName="scroll" Path="Value"/>

                </Label.Content>

            </Label>

        </StackPanel>

    </Grid>

 

중괄호 내에 Binding 정의가 있으며, Binding 클래스의 프로퍼티 중 ElementName와 Path가 이 정의에 포함된다. 이 Binding 정의에서 ElementName은 ScrollBar의 Name속성에 부여된 이름인 scroll로 설정되고 Binding의 Path 프로퍼티는 Value로 설정되는데, 이 컨텍스트에서는 ScrollBar의 Value프로퍼티이다. 그 후 Label의 Content 프로퍼티는 ScrollBar의 Value프로퍼티와 바인딩되어 ScrollBar의 조작에 따라 값이 Label에 출력된다.



바인딩은 4가지의 모드를 가지고 있다.
OneWay, TwoWay, OneTime, OneWayTosource로 나열할 수 있다.

기본적인 형태는 아래와 같다. 

<Label HorizontalAlignment="Center"

Content="{Binding ElementName=scroll, Path=Value, Mode=OneWay}" />

 

또한 모드를 TwoWay로 설정할 수도 있다. 

<Label HorizontalAlignment="Center"

Content="{Binding ElementName=scroll, Path=Value, Mode=TwoWay}" />

이 프로그램에서 TwoWay는 기능상 OneWay와 동일하지만 실제로는 Label의 Content 프로퍼티의 변화도 ScrollBar의 Value프로퍼티에 반영된다. 

<Label HorizontalAlignment="Center"

Content="{Binding ElementName=scroll, Path=Value, Mode=OneTime}" />

 OneTime의 경우 타깃이 소스로부터 초기화되지만 소스의 변화가 계속적으로 반영되지 않고 초기에 한번만 반영된다. 이 프로그래에서는 ScrollBar의 초기 Value가 0이기 때문에 Label이 0을 표시하며, 표시된 값은 ScrollBar의 변화에 더 이상 반응하지 않는다.

 

<Label HorizontalAlignment="Center"

Content="{Binding ElementName=scroll, Path=Value, Mode=OneWayToSource}" />

 이것은 일반적으로 생각하는 소스와 타깃의 의미에 반대되게 타깃이 소스를 갱신하는 형태이다. 마치 과녁이 거꾸로 화살 쪽으로 날아와 과녁의 중심을 스스로 찌르는 듯한 형태라고 볼 수 있다. 따라서 타깃(Label)은 소스(ScrollBar)를 갱신해야 한다.

DataContext 프로퍼티가 상당히 유용할 때가 있는데, DataContext가 엘리먼트 트리를 통해 상속되기 때문에 하나의 엘리먼트에 DataContext를 사용해 바인딩을 설정하면 aems 자식 엘리먼트에도 동일하게 적용된다.

<Grid>

        <StackPanel VerticalAlignment="Center" DataContext="{Binding ElementName=scroll}">

            <ScrollBar Name="scroll" Orientation="Horizontal" Margin="24" Maximum="100" LargeChange="10"  SmallChange="1"/>

            <Label HorizontalAlignment="Center" Content="{Binding Path=Value, Mode=OneWay}" />

            <Button HorizontalAlignment="Center" Margin="24" FontSize="{Binding Path=Value, Mode=OneWay}">Bound Button</Button>

        </StackPanel>

    </Grid>

DataContext StackPanel엘리먼트에서 한 번 설정되었고 Label Button ScrollBar와 바운딩됐다. Label에 바운딩된 프로퍼티는 Context이지만 Button에 바운딩된 프로퍼티는 FontSize이기 때문에 ScrollBar의 막대를 움직이면 Button 내부의 텍스트가 점점 커지고 이에 따라 Button 자체도 커지게 된다.







저작자 표시
신고

'Study > WPF' 카테고리의 다른 글

[WPF_Program: Window Desktop Interface]  (3) 2011.02.12
[WPF: insert XAML into RichTextBox]  (0) 2010.12.20
[WPF: Diagramming. Saving you canvas to image]  (0) 2010.10.20
[WPF : Data Binding]  (0) 2010.07.28
Trackback 0 | Comment 0
데이터 바인딩이란 컨트롤과 엘리먼트를 데이터에 연결시키는 기술이다. 이 정의가 약간 모호할 수있는데, 이것은 데이터 바인딩이 굉장히 넓은 범위와 다양한 기술을 포함하기 때문이다. 데이터 바인딩은  CheckBox 컨트롤을 불리언 변수에 연결하는 것처럼 간단할 수 있고 데이터베이스와 데이터 엔트리 패널을 연결하는 것처럼 복잡해 질 수도 있다.
컨트롤은 데이터를 사용자에게 보여주는 것과 사용자가 데이터를 변경할 수 있게 해주는 2가지 기능을 제공한다.
가장 간단한 바인딩은 2개의 컨트롤 사이에서 존재하는 것이다. 예를 들어 ScrollBar의 Value 프로퍼티를 보여주기 위한 Label 컨트롤을 생각해보자. 이 경우 Scrollbar의 ValueChanged 이벤트 핸들러를 연결하거나 다음의 스탠드얼론 XAML 파일과 같이 데이터 바인딩을 정의할 수 있다.

<Grid>

        <StackPanel VerticalAlignment="Center">

           <ScrollBar Name="scroll" Orientation="Horizontal"

Margin="24" Maximum="100" LargeChange="10"                                       SmallChange="1"/>

            <Label HorizontalAlignment="Center"

Content="{Binding ElementName=scroll, Path=Value}" />

        </StackPanel>

    </Grid>



<Grid>

        <StackPanel VerticalAlignment="Center">

            <ScrollBar Name="scroll" Orientation="Horizontal"

Margin="24" Maximum="100" LargeChange="10"                       SmallChange="1"/>

            <Label HorizontalAlignment="Center">

                <Label.Content>

                    <Binding ElementName="scroll" Path="Value"/>

                </Label.Content>

            </Label>

        </StackPanel>

    </Grid>

 

중괄호 내에 Binding 정의가 있으며, Binding 클래스의 프로퍼티 중 ElementName와 Path가 이 정의에 포함된다. 이 Binding 정의에서 ElementName은 ScrollBar의 Name속성에 부여된 이름인 scroll로 설정되고 Binding의 Path 프로퍼티는 Value로 설정되는데, 이 컨텍스트에서는 ScrollBar의 Value프로퍼티이다. 그 후 Label의 Content 프로퍼티는 ScrollBar의 Value프로퍼티와 바인딩되어 ScrollBar의 조작에 따라 값이 Label에 출력된다.



바인딩은 4가지의 모드를 가지고 있다.
OneWay, TwoWay, OneTime, OneWayTosource로 나열할 수 있다.

기본적인 형태는 아래와 같다. 

<Label HorizontalAlignment="Center"

Content="{Binding ElementName=scroll, Path=Value, Mode=OneWay}" />

 

또한 모드를 TwoWay로 설정할 수도 있다. 

<Label HorizontalAlignment="Center"

Content="{Binding ElementName=scroll, Path=Value, Mode=TwoWay}" />

이 프로그램에서 TwoWay는 기능상 OneWay와 동일하지만 실제로는 Label의 Content 프로퍼티의 변화도 ScrollBar의 Value프로퍼티에 반영된다. 

<Label HorizontalAlignment="Center"

Content="{Binding ElementName=scroll, Path=Value, Mode=OneTime}" />

 OneTime의 경우 타깃이 소스로부터 초기화되지만 소스의 변화가 계속적으로 반영되지 않고 초기에 한번만 반영된다. 이 프로그래에서는 ScrollBar의 초기 Value가 0이기 때문에 Label이 0을 표시하며, 표시된 값은 ScrollBar의 변화에 더 이상 반응하지 않는다.

 

<Label HorizontalAlignment="Center"

Content="{Binding ElementName=scroll, Path=Value, Mode=OneWayToSource}" />

 이것은 일반적으로 생각하는 소스와 타깃의 의미에 반대되게 타깃이 소스를 갱신하는 형태이다. 마치 과녁이 거꾸로 화살 쪽으로 날아와 과녁의 중심을 스스로 찌르는 듯한 형태라고 볼 수 있다. 따라서 타깃(Label)은 소스(ScrollBar)를 갱신해야 한다.

DataContext 프로퍼티가 상당히 유용할 때가 있는데, DataContext가 엘리먼트 트리를 통해 상속되기 때문에 하나의 엘리먼트에 DataContext를 사용해 바인딩을 설정하면 aems 자식 엘리먼트에도 동일하게 적용된다.

<Grid>

        <StackPanel VerticalAlignment="Center" DataContext="{Binding ElementName=scroll}">

            <ScrollBar Name="scroll" Orientation="Horizontal" Margin="24" Maximum="100" LargeChange="10"  SmallChange="1"/>

            <Label HorizontalAlignment="Center" Content="{Binding Path=Value, Mode=OneWay}" />

            <Button HorizontalAlignment="Center" Margin="24" FontSize="{Binding Path=Value, Mode=OneWay}">Bound Button</Button>

        </StackPanel>

    </Grid>

DataContext StackPanel엘리먼트에서 한 번 설정되었고 Label Button ScrollBar와 바운딩됐다. Label에 바운딩된 프로퍼티는 Context이지만 Button에 바운딩된 프로퍼티는 FontSize이기 때문에 ScrollBar의 막대를 움직이면 Button 내부의 텍스트가 점점 커지고 이에 따라 Button 자체도 커지게 된다.







저작자 표시
신고

'Study > WPF' 카테고리의 다른 글

[WPF_Program: Window Desktop Interface]  (3) 2011.02.12
[WPF: insert XAML into RichTextBox]  (0) 2010.12.20
[WPF: Diagramming. Saving you canvas to image]  (0) 2010.10.20
[WPF : Data Binding]  (0) 2010.07.28
Trackback 0 | Comment 0

강군v's Blog is powered by Daum & tistory

 

티스토리 툴바