views:

167

answers:

2

What can I do if I want to have a text-box representing in real time the value of a loop counter in wpf?

appending working solution:

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
    }

    private delegate void UpdateTextBox(DependencyProperty dp, Object value);
...
private void MyMethod()
{
    ...
    int iMax=...;
    ...
    MyClass iMyClass = new MyClass(arguments);
        this.DataContext = iMyClass;
        UpdateTextBox updateTBox = new UpdateTextBox(textBlock1.SetValue);
        for (int i = 1; i <= iMax; i++)
        {
            iMyClass.MyClassMethod(i);
            Dispatcher.Invoke(updateTBox, System.Windows.Threading.DispatcherPriority.Background, new object[] { MyClass.MyPropertyProperty, iMyClass.myProperty });

        }

Here is the code I tried according to your suggestion, but it doesnt work, I get "0" written in the textbox, so I suppose the binding is OK, but the loop doesnt work. I also made the loop to write into another textbox directly by textbox2.text="a" inside the loop, but it didnt work either.

/// <summary>
/// Interaction logic for Window1.xaml
/// DOESNT WORK PROPERLY
/// </summary>
public partial class Window1 : Window
{


    public Window1()
    {
        InitializeComponent();
        TestClass tTest = new TestClass();
        this.DataContext = tTest ;
        tTest.StartLoop();
    }
}
public class TestClass : DependencyObject
{
    public TestClass()
    {
        bwLoop = new BackgroundWorker();

        bwLoop.DoWork += (sender, args) =>
        {

            // do your loop here -- this happens in a separate thread
            for (int i = 0; i < 10000; i++)
            {
                LoopCounter=i;
            }
        };
    }
    BackgroundWorker bwLoop;

    public int LoopCounter
    {
        get { return (int)GetValue(LoopCounterProperty); }
        set { SetValue(LoopCounterProperty, value); }
    }

    public static readonly DependencyProperty LoopCounterProperty = DependencyProperty.Register("LoopCounter", typeof(int), typeof(TestClass));

    public void StartLoop()
    {
        bwLoop.RunWorkerAsync();
    }
}

}

A: 

you can use Data Binding for continuously updating the text.

viky
+2  A: 
  1. Run the loop in a background process (so that the UI can update itself while the loop is running) and

  2. write the loop counter into a property (DependencyProperty or CLR property with INotifyPropertyChanged) which is bound to a TextBox in your user interface. Alternatively, you can directly change the value of the TextBox via Dispatcher.Invoke (this is less elegant, though).

Does this help? Feel free to ask for clarification...


Code example (untested), using a DependencyProperty (which must be bound to a TextBox):

BackgroundWorker bwLoop;
public static readonly DependencyProperty LoopCounterProperty = 
    DependencyProperty.Register("LoopCounter", typeof(int),
    typeof(Window1), new FrameworkPropertyMetadata(0));

public int LoopCounter  {
    get { return (int)this.GetValue(LoopCounterProperty); }
    set { this.SetValue(LoopCounterProperty, value); } 
}

private MyWindow() {
    ...
    bwLoop = new BackgroundWorker();

    bwLoop.DoWork += (sender, args) => {
        ...
        for (int i = 0; i < someLimit; i++) {
            Dispatcher.Invoke(new Action(() => LoopCounter=i));
            System.Threading.Thread.Sleep(250); // do your work here
        }
    }

    bwLoop.RunWorkerCompleted += (sender, args) => {
        if (args.Error != null)
            MessageBox.Show(args.Error.ToString());
    };
}

private void StartLoop() {
    bwLoop.RunWorkerAsync();
}
Heinzi
i managed to do it with DependancyProperty and Dispatcher.Invoke.Could you please elaborate more on the first possiblity - run the loop in a background process and write the loop counter in a dependency property. is it different from what i did?
butaro
I've added a code example, so you can compare it with your code. If you add your code to your question, I could comment on it.
Heinzi
i did, is it clear what i did?
butaro
ok, what you gave me really looks very elegant, and easy to understand. I have to go to bed now (it is 3am here). Will check it tomorrow, thanks a lot!!!
butaro
I see, thanks. How do you call MyMethod? If you do it just by calling it, I'm a bit surprised that it works, since then it's running in the same thread as the rest of the application.
Heinzi
actualy MyMethod is a button_OnClick method that runs when i click a button on the window
butaro
i cant make your example work
butaro
Is LoopCounter bound to your textbox? I've added the DependencyProperty declaration details to my answer.
Heinzi
actually, I wasnt able to use dependencyProperty in Window1, because I get error "cannot implement two base types" when i try this: Window1: Window, DependencyObject.So I did it in anothother class in the way that you wrote (except for the , new FrameworkPropertyMetadata(0) part, but adding it didnt change a thing). I will paste shortly my code in my question
butaro
You don't need to add DependencyObject, since `Window` already derives from DependencyObject!
Heinzi
well, look at my code, i pasted it, and if you can find where it is wrong, i would appreciate it. It seems to me that if your code should work mine should too
butaro
You are right of course, there was a bug in my code, shame on me. Setting LoopCounter must be done with Dispatcher.Invoke, since dependency properties can only be set by the thread in which they were created. I've update my answer. I also added a message box if an error occurs in the thread; this has helped me debug the problem.
Heinzi