Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Console Application and WPF

43 views
Skip to first unread message

shapper

unread,
Nov 19, 2009, 12:30:57 PM11/19/09
to
Hello,

I have a Console application that performs some actions and in the
window I can see text that is saying what is doing.
I know created a WPF application with the same code.

Is it possible to show the same output text in a TextBlock?

Thanks,
Miguel

Peter Duniho

unread,
Nov 19, 2009, 1:21:47 PM11/19/09
to

Yes. You could redirect the standard output of the Console class by
calling SetOut(). But IMHO a better way would be to abstract your
output via a custom class (e.g. a subclass of TextWriter you've
created), and then use that abstraction to allow for the output to
continue to go to the Console's standard output while intercepting it
for your WPF control.

Pete

shapper

unread,
Nov 19, 2009, 4:09:15 PM11/19/09
to
On Nov 19, 6:21 pm, Peter Duniho <no.peted.s...@no.nwlink.spam.com>
wrote:

> Yes.  You could redirect the standard output of the Console class by
> calling SetOut().  But IMHO a better way would be to abstract your
> output via a custom class (e.g. a subclass of TextWriter you've
> created), and then use that abstraction to allow for the output to
> continue to go to the Console's standard output while intercepting it
> for your WPF control.

I am not sure if I fully understand what you are saying but I am
starting as follows:

private class ConsoleLog : TextWriter {

private TextWriter _writer;
private TextBlock _output;

public ConsoleLog(TextBlock output, TextWriter writer) {
_writer = writer;
_output = output;
} // ConsoleLog

public override void Write(String s) {

_writer.Write(s);
_output.Text = String.Concat(_output.Text, s);

} // Write

} // ConsoleLog

_writer should be the original writer and output should be the
TextBlock control where I would like to display the output.

Then I would use something like:

using (ConsoleLog cl = new ConsoleLog(tbOutput, Console.Out)) {
Console.SetOut(cl);
}

Is this what you mean?

Thanks,
Miguel

Peter Duniho

unread,
Nov 19, 2009, 5:45:48 PM11/19/09
to
shapper wrote:
> [...]

> Then I would use something like:
>
> using (ConsoleLog cl = new ConsoleLog(tbOutput, Console.Out)) {
> Console.SetOut(cl);
> }
>
> Is this what you mean?

Not quite, but that approach looks like it should work too.

What I really meant was for you to have a class like your ConsoleLog
class, which you use _instead_ of the Console class directly for your
logging. That class would then handle directing the output as desired
(either to the TextBlock, to the Console, or both).

There are lots of different ways you can do this. Just pick the one
that seems to fit your existing architecture the best.

Pete

shapper

unread,
Nov 19, 2009, 6:36:04 PM11/19/09
to
On Nov 19, 10:45 pm, Peter Duniho <no.peted.s...@no.nwlink.spam.com>
wrote:

> Not quite, but that approach looks like it should work too.

On Nov 19, 10:45 pm, Peter Duniho <no.peted.s...@no.nwlink.spam.com>
wrote:


> Not quite, but that approach looks like it should work too.

I was missing:
public override Encoding Encoding { get { return Encoding.Default; } }

But I think I found what do you mean:
http://dpatrickcaldwell.blogspot.com/2008/12/using-proxy-pattern-to-write-to.html

If this is what you meant I think it is really interesting.

I am not quite sure how to use it with a TextBlock ... To keep being
updated.
But I am going to give it a try.

shapper

unread,
Nov 20, 2009, 12:08:31 PM11/20/09
to
Hi,

I am using the TextWriterProxy in the WPF application as follows:

TextBlock output = new TextBlock();

TextWriterProxy proxy = new TextWriterProxy();
proxy.Add(Console.Out);

StringBuilder sb = new StringBuilder();
StringWriter resultStringWriter = new StringWriter(sb);
proxy.Add(resultStringWriter);
output.Text = sb.ToString();

However, text block does not show any text. Any idea how to do this
integration?

The TextWriterProxy code is as follows:

public class TextWriterProxy : TextWriter {

private List<TextWriter> _writers = new List<TextWriter>();

public override Encoding Encoding { get { return

Encoding.Default; } } // Encoding

public override string NewLine {
get { return base.NewLine; }
set {
foreach (TextWriter tw in _writers)
tw.NewLine = value;
base.NewLine = value;
}
} // NewLine

public void Add(TextWriter writer) {
if (!_writers.Contains(writer))
_writers.Add(writer);
} // Add

public bool Remove(TextWriter writer) {
return _writers.Remove(writer);
} // Remove

public override void Write(char value) {
foreach (TextWriter tw in _writers)
tw.Write(value);
base.Write(value);
} // Write

public override void Close() {
foreach (TextWriter tw in _writers)
tw.Close();
base.Close();
} // Close

protected override void Dispose(bool disposing) {
foreach (TextWriter tw in _writers)
tw.Dispose();
base.Dispose(disposing);
} // Dispose

public override void Flush() {
foreach (TextWriter tw in _writers)
tw.Flush();
base.Flush();
} // Flush

} // TextWriterProxy

Thanks,
Miguel

Peter Duniho

unread,
Nov 20, 2009, 1:41:21 PM11/20/09
to
shapper wrote:
> Hi,
>
> I am using the TextWriterProxy in the WPF application as follows:
>
> TextBlock output = new TextBlock();
>
> TextWriterProxy proxy = new TextWriterProxy();
> proxy.Add(Console.Out);
>
> StringBuilder sb = new StringBuilder();
> StringWriter resultStringWriter = new StringWriter(sb);
> proxy.Add(resultStringWriter);
> output.Text = sb.ToString();
>
> However, text block does not show any text. Any idea how to do this
> integration?

Not without a concise-but-complete code example.

The code you posted does not in and of itself show anything that should
necessarily add text to your TextBlock class. The StringWriter you've
added to your proxy isn't going to have any text in it until you
actually write some text to the proxy. In the code you show, the only
time you set the Text property of your TextBlock is immediately after
initializing the proxy, before you've actually written anything to it.

It seems to me that if you want immediate updates in your TextBlock
according to writes to the proxy, you need a custom TextWriter (in
addition to the proxy, or just make the proxy understand the TextBlock
instance specifically) that when written to, it updates the TextBlock
accordingly (by adding the text to the TextBlock's current text).

Pete

shapper

unread,
Nov 20, 2009, 2:12:54 PM11/20/09
to
On Nov 20, 6:41 pm, Peter Duniho <no.peted.s...@no.nwlink.spam.com>
wrote:

> Not without a concise-but-complete code example.
>
> The code you posted does not in and of itself show anything that should
> necessarily add text to your TextBlock class.  The StringWriter you've
> added to your proxy isn't going to have any text in it until you
> actually write some text to the proxy.  

Sorry, I am very familiar with WPF and console.
I would create an full code example if I could replicate what I am
doing.

I have the following example which hopefully will explain what I am
trying to do:

DockPanel content = new DockPanel();


TextBlock output = new TextBlock();
TextWriterProxy proxy = new TextWriterProxy();
proxy.Add(Console.Out);

StringBuilder sb = new StringBuilder();
StringWriter resultStringWriter = new StringWriter(sb);
proxy.Add(resultStringWriter);

proxy.WriteLine("Start");
PackService.Run();
proxy.WriteLine("Finish");
output.Text = sb.ToString();

DockPanel.SetDock(output, Dock.Bottom);
content.Children.Add(output);
Content = content;

PackService.Run() minimizes some CSS and JS code. So in console I get:

Start
Writing output to C:\Users\Miguel\Projects\WCA.Presentation\Scripts
\WCA.Site.min.js
Writing output to C:\Users\Miguel\Projects\WCA.Presentation\Scripts
\JQuery-1.3.2.Plugins.min.js
Writing output to C:\Users\Miguel\Projects\WCA.Presentation\Styles
\WCA.Base.min.css
Finish

I would like to "see" this on my Text Block but I get only:
Start
Finish

In fact I would like the TextBlock to match what is shown in console
and in every part of my code, for example, even inside PackService.Run
() to be able to send something to console that would also show in
TextBlock.

Am I explaining this correctly?

Thank You,
Miguel


shapper

unread,
Nov 20, 2009, 2:20:39 PM11/20/09
to
I took another small step to solve this:

Console.SetOut(proxy);


proxy.WriteLine("Start");
PackService.Run();
proxy.WriteLine("Finish");
output.Text = sb.ToString();

Now I "see" all the lines on my TextBlock.

The problem is that if I click a button on my WPF menu that calls
PackService.Run() in this case nothing happens on the TextBox.

My idea would make all my application aware of the proxy and that
SetOut(proxy) ... Is this possible?

Peter Duniho

unread,
Nov 20, 2009, 2:25:00 PM11/20/09
to
shapper wrote:
> [...]

> In fact I would like the TextBlock to match what is shown in console
> and in every part of my code, for example, even inside PackService.Run
> () to be able to send something to console that would also show in
> TextBlock.
>
> Am I explaining this correctly?

I don't know. As I said, a concise-but-complete code example would go a
long way to improving your question.

That said, if I understand correctly, the problem is that your
PackService.Run() method is still writing directly to the Console class.
It should use your proxy class instead.

Though, that said, your original choice to redirect the Console standard
output by calling SetOut() should also work, and wouldn't require
changes to the PackService.Run() method. Just because my original
suggestion was different from what you thought I meant, or different
from some other approach that might work, that doesn't mean you have to
follow my original suggestion.

Beyond that, it's really impossible to provide specific advice without a
specific question.

Pete

Peter Duniho

unread,
Nov 20, 2009, 2:47:43 PM11/20/09
to
shapper wrote:
> [...]

> My idea would make all my application aware of the proxy and that
> SetOut(proxy) ... Is this possible?

Just create the proxy at the beginning of your program, and call
Console.SetOut() with the proxy before any of the stuff happens for
which you want output.

shapper

unread,
Nov 20, 2009, 4:18:05 PM11/20/09
to
On Nov 20, 7:25 pm, Peter Duniho <no.peted.s...@no.nwlink.spam.com>
wrote:

> I don't know.  As I said, a concise-but-complete code example would go a


> long way to improving your question.

I am not sure if the example that you are asking is what I am going to
post.

The objectives are:
1. Display the result of Console.WriteLine in Console and in
TextBlock ...
... From Window1 and from Test.Run() when the button is clicked.

2. Write the result of a command in Console and TextBlock ...
In my code I was checking the messages of minimizing the JS and CSS
code.
I didn't implement this part. Maybe saving or opening a file?

I think the TextWriterProxy would be a better option than my initial
approach as it even allows to write to other targets.

This said, this is my code (I hope this is what you are asking):

-- BEGIN Window1.xaml ---

<Window x:Class="ConsoleTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
</Window>


-- BEGIN Window1.xaml.cs ---

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;

// ConsoleTest
namespace ConsoleTest {

public partial class Window1: Window {

#region Constructors

public Window1() {

// Initialize component
InitializeComponent();

// Define proxy


TextWriterProxy proxy = new TextWriterProxy();
proxy.Add(Console.Out);
StringBuilder sb = new StringBuilder();

StringWriter sw = new StringWriter(sb);
proxy.Add(sw);
Console.SetOut(proxy);

// Dock panel


DockPanel content = new DockPanel();

// Menu
Menu menu = new Menu();
menu.Items.Add(new MenuItem { Command = TestCommands.Test,
Header = "Test" });
DockPanel.SetDock(menu, Dock.Top);
content.Children.Add(menu);

// Text block


TextBlock output = new TextBlock();

DockPanel.SetDock(output, Dock.Bottom);
content.Children.Add(output);
Content = content;

// 1: Use Text Writer Proxy - NOT WORKING FROM Test.Run()
proxy.WriteLine("Write from Window1");
output.Text = sb.ToString();

// 2: Use Console Log - NOT WORKING
//using (ConsoleLog cl = new ConsoleLog(output, Console.Out)) {
// Console.SetOut(cl);
//}
//Console.WriteLine("Write from Window1");

} // Start

#endregion // Constructors

} // Start

} // ConsoleTest

// ConsoleLog
public class ConsoleLog : TextWriter {

public override Encoding Encoding { get { return
Encoding.Default; } } // Encoding

private TextWriter _writer;
private TextBlock _output;

public ConsoleLog(TextBlock output, TextWriter writer) {
_writer = writer;
_output = output;
} // ConsoleLog

public override void Write(String s) {

_writer.Write(s);
_output.Text = String.Concat(_output.Text, s);

} // Write

} // ConsoleLog

// TestCommands
public static class TestCommands {

public static ICommand Test { get { return new TestCommand(); } }

public class TestCommand : ICommand {

// CanExecute
public Boolean CanExecute(Object parameter) {
return true;
} // CanExecute

// CanExecuteChanged
public event EventHandler CanExecuteChanged {
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
} // CanExecuteChanged

// Execute
public void Execute(Object parameter) {
TestService.Run();
} // Execute

} // TestCommand

} // TestCommands

// TestService
public static class TestService {

#region Methods

public static void Run() {
Console.WriteLine("Write from Test Service");
} // Run

#endregion // Methods

} // TestService

public class TextWriterProxy : TextWriter {

} // TextWriterProxy


Thank You,
Miguel

Peter Duniho

unread,
Nov 20, 2009, 5:07:53 PM11/20/09
to
shapper wrote:
> On Nov 20, 7:25 pm, Peter Duniho <no.peted.s...@no.nwlink.spam.com>
> wrote:
>
>> I don't know. As I said, a concise-but-complete code example would go a
>> long way to improving your question.
>
> I am not sure if the example that you are asking is what I am going to
> post.
>
> The objectives are:
> 1. Display the result of Console.WriteLine in Console and in
> TextBlock ...
> ... From Window1 and from Test.Run() when the button is clicked.
>
> 2. Write the result of a command in Console and TextBlock ...
> In my code I was checking the messages of minimizing the JS and CSS
> code.
> I didn't implement this part. Maybe saving or opening a file?
>
> I think the TextWriterProxy would be a better option than my initial
> approach as it even allows to write to other targets.
>
> This said, this is my code (I hope this is what you are asking): [...]

Well, the code you posted isn't complete, because you call a method not
declared in the code you posted (InitializeComponent()).

That said, the code you did post looks much like the code I already
responded to, where I explained that simply redirecting the output to
your proxy which in turn redirects output to your StringWriter cannot in
and of itself cause any update to the TextBlock control.

As I wrote before, you need some mechanism for specifically updating the
TextBlock control any time something is written to your proxy. For
example, yet another TextWriter that wraps updates to the TextBlock
control. Add that TextWriter to your proxy (which is really a kind of
"T filter"), and then in that TextWriter, copy text passed via the
Write() method to the TextBlock.

Nothing about the expanded code example you've posted leads me to change
my mind on that point. :)

Pete

shapper

unread,
Nov 21, 2009, 1:18:47 PM11/21/09
to
On Nov 20, 10:07 pm, Peter Duniho <no.peted.s...@no.nwlink.spam.com>

wrote:
> shapper wrote:
> > On Nov 20, 7:25 pm, Peter Duniho <no.peted.s...@no.nwlink.spam.com>
> > wrote:
>
> >> I don't know.  As I said, a concise-but-complete code example would go a
> >> long way to improving your question.
>
> > I am not sure if the example that you are asking is what I am going to
> > post.
>
> > The objectives are:
> > 1. Display the result of Console.WriteLine in Console and in
> > TextBlock ...
> >    ... From Window1 and from Test.Run() when the button is clicked.
>
> > 2. Write the result of a command in Console and TextBlock ...
> >    In my code I was checking the messages of minimizing the JS and CSS
> > code.
> >    I didn't implement this part. Maybe saving or opening a file?
>
> > I think the TextWriterProxy would be a better option than my initial
> > approach as it even allows to write to other targets.
>
> > This said, this is my code (I hope this is what you are asking): [...]
>
> Well, the code you posted isn't complete, because you call a method not
> declared in the code you posted (InitializeComponent()).

It is a part of WPF code and is present in all Windows or User
Controls. A better description:

"The call to InitializeComponent() (which is usually called in the
default constructor of at least Window and UserControls) is actually a
method call to the partial class of the control (rather than a call up
the object hierarchy as I first expected).

This method locates a URI to the XAML for the Window/UserControl that
is loading, and passes it to the
System.Windows.Application.LoadComponent() static method. LoadComponent
() loads the XAML file that is located at the passed in URI, and
converts it to an instance of the object that is specified by the root
element of the XAML file.

In more detail, LoadComponent creates and instance of the XamlParser,
and builds a tree of the XAML. Each node is parsed by the
XamlParser.ProcessXamlNode(). This gets passed to the BamlRecordWriter
class. Sometime after this I get a bit lost in how the BAML is
converted to objects, but this may be enough to help you on the path
to enlightenment.

Note: Interestingly, the InitializeComponent is an method on the
System.Windows.Markup.IComponentConnector interface, of which Window/
UserControls implement in the partial generated class."

> That said, the code you did post looks much like the code I already
> responded to, where I explained that simply redirecting the output to
> your proxy which in turn redirects output to your StringWriter cannot in
> and of itself cause any update to the TextBlock control.
>
> As I wrote before, you need some mechanism for specifically updating the
> TextBlock control any time something is written to your proxy.  For
> example, yet another TextWriter that wraps updates to the TextBlock
> control.  Add that TextWriter to your proxy (which is really a kind of
> "T filter"), and then in that TextWriter, copy text passed via the
> Write() method to the TextBlock.

I am a little bit lost about the code you suggesting but what comes to
mind is to add a ConsoleLog to the proxy.
Since ConsoleLog already implements TextWriter and works with
TextBlock ...

But I think I need to make some changes in it ... I am confused. :-)

> Nothing about the expanded code example you've posted leads me to change
> my mind on that point.  :)

See that my "strange" initial code said it all? :-P

Miguel

Peter Duniho

unread,
Nov 21, 2009, 2:13:23 PM11/21/09
to
shapper wrote:
> [...]

>> Nothing about the expanded code example you've posted leads me to change
>> my mind on that point. :)
>
> See that my "strange" initial code said it all? :-P

No. It's just that your subsequent post didn't add anything to it.

shapper

unread,
Nov 24, 2009, 8:41:17 AM11/24/09
to
On Nov 21, 7:13 pm, Peter Duniho <no.peted.s...@no.nwlink.spam.com>
wrote:

I a not sure but maybe turning the proxy into a static class would
make it globally and solve the problem.

I am trying the following:

public partial class Window1 : Window
{

public Window1()
{
InitializeComponent();

ConsoleWriter.TextBlock = tbOutput;
ConsoleWriter.WriteLine("TEST");
}
}

public static class ConsoleWriter
{
public static TextBlock TextBlock { get; set; }

public static void WriteLine(string message)
{
Console.WriteLine(message);
TextBlock.Text = message;
}
}

But instead of using this approach maybe have the ConsoleWriter wrapp
the TextBlock and the Proxy ..

0 new messages