如何刷新线程中的文本框绑定

时间:2017-06-23 12:38:14

标签: c# wpf multithreading binding

以下代码是解释我的问题的示例。

我有一个绑定文本框。当我单击按钮时,执行一个功能。 (在这种情况下,它是 for loop )。

现在我想要,文本框更新了 i 变量的内容。 ( public void MyAction())

所以,我制作了一个帖子,但这不起作用。

为什么?

提前致谢

XAML代码

<TextBox Text ="{Binding MyValue}" HorizontalAlignment="Left" Height="47" Margin="4,4,4,4" VerticalAlignment="Top" Width="342"/>
<Button Command="{Binding ClickCommand}" Content="Run" Margin="114,69,283,216"/>

C#代码

    class Vm_Main : ViewModelBase
{
    public string _MyValue { get; set; }  //String in my XAML
    public string MyValue
    {
        get { return _MyValue; }
        set
        {
            _MyValue = value;
            base.OnPropertyChanged("MyValue");
        }
    }

    private bool _canExecute=true;
    private ICommand _clickCommand;
    public ICommand ClickCommand
    {
        get
        {
            return _clickCommand ?? (_clickCommand = new CommandHandler(() => MyAction(), _canExecute));
        }
    }


    public Vm_Main()
    {
        MyValue = "Hallo"; //Default value
    }

    public void MyAction() // This is the function where I want update the TextBox in Binding
    {
        Worker workerObject = new Worker();
        Thread workerThread = new Thread(workerObject.DoWork);
        workerThread.Start();

        for (int i = 1; i <= 10; i++)
        {
            MyValue = i.ToString();
            workerObject.Value = MyValue;
            Thread.Sleep(500);
        }
        workerObject.RequestStop();
        workerThread.Join();
        MessageBox.Show("End");
    }
}

// The THREAD
public class Worker : ViewModelBase 
{
    // This method will be called when the thread is started.
    public string _Value { get; set; }
    public string Value
    {
        get { return _Value; }
        set
        {
            _Value = value;
            base.OnPropertyChanged("Value");
        }
    }
    public void DoWork()
    {
        while (!_shouldStop)
        {
            Console.WriteLine("Value is..." + _Value);
        }
        Console.WriteLine("End.");
    }
    public void RequestStop()
    {
        _shouldStop = true;
    }
    // Volatile is used as hint to the compiler that this data
    // member will be accessed by multiple threads.
    private volatile bool _shouldStop;
}

Class ViewModelBase和Class Command

    public abstract class ViewModelBase : INotifyPropertyChanged
{
    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string strPropertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(strPropertyName));
    }
    #endregion



    #region Messages and Progressbar
    private string _errorMessage;
    public string ErrorMessage
    {
        get { return _errorMessage; }
        set
        {
            if (_errorMessage == value) return;
            _errorMessage = value;
            OnPropertyChanged("ErrorMessage");
        }
    }

    private string _errorTooltip;
    public string ErrorTooltip
    {
        get { return _errorTooltip; }
        set
        {
            if (_errorTooltip == value) return;
            _errorTooltip = value;
            this.OnPropertyChanged("ErrorTooltip");
        }
    }

    private string _statusMessage;
    public string StatusMessage
    {
        get { return _statusMessage; }
        set
        {
            if (_statusMessage == value) return;
            _statusMessage = value;
            //pulizia dei messaggi di errore
            ErrorMessage = string.Empty;
            ErrorTooltip = string.Empty;
            OnPropertyChanged("StatusMessage");
        }
    }

    protected void ClearMessage()
    {
        ErrorMessage = string.Empty;
        StatusMessage = string.Empty;
    }

    private int _currentProgress;
    public int CurrentProgress
    {
        get { return _currentProgress; }
        set
        {
            _currentProgress = value;
            OnPropertyChanged("CurrentProgress");
        }
    }
    #endregion

    protected ViewModelBase()
    {

    }
}


    public class CommandHandler : ICommand
{
    private Action _action;
    private bool _canExecute;
    public CommandHandler(Action action, bool canExecute)
    {
        _action = action;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        _action();
    }
}

1 个答案:

答案 0 :(得分:0)

所以我认为你必须解决问题。

首先使用async await模式。

就是这样 - 不阻止你的UI线程。

public async Task<object> MyAsyncMethod()
{
    return await Task.Run<object>(() =>
    {
        return null;
    });
}

ICommand只是:

public async void MyAsyncMethod()
{
    await Task.Run(() =>
    {

    });
}

第二是您可能希望在处理异步时更新UI。例如,这是更新进度的常见问题。您可以使用SynchronizationContext解决此问题。

public interface IUpdateProgess
{
    void SendMessage(string val);
}



public async Task<object> MyAsyncMethod(IUpdateProgess progress)
{
    //UI thread
    SynchronizationContext context = SynchronizationContext.Current;

    return await Task.Run<object>(() =>
    {
        //other thread


        if (context != null && progress != null)
        {
            context.Post(new SendOrPostCallback((o) =>
            {
                progress.SendMessage("Progress");
            }), null);
        }

        return null;
    });
}

你可以使用这显然不仅仅是更新进度 - 我想你明白了。