【问题标题】:async SMS sending function is not getting data from textbox WPF c#异步短信发送功能未从文本框 WPF c# 获取数据
【发布时间】:2016-02-24 20:03:11
【问题描述】:

我正在尝试通过在循环中从网格视图中获取数据来创建一个异步函数来一一发送文本消息。

到目前为止,我所做的事情如下:

 public async void asyncSmsSend()
    {
        try
        {
            btnSend.Content = "Sending...";

            await sendSmsFunc();

            btnSend.Content = "Sent";
        }
        catch (Exception)
        {

            throw;
        }
    }

    private Task sendSmsFunc()
    {
        return Task.Factory.StartNew(() =>
        {
            try
            {
                srprt = new SerialPort(prt, 115200);
                Thread.Sleep(1000);

                srprt.Open();

                Thread.Sleep(1000);

                srprt.Write("AT+CMGF=1\r");
                Thread.Sleep(1000);

                srprt.Write("AT+CMGS=\"" +tbNmber.Text+ "\"\r\r");
                Thread.Sleep(1000);

                srprt.Write(tbMessage.Text + "\x1A");
                Thread.Sleep(1000);

                //btnSend.Content = "Sent";
                srprt.Close();
            }
            catch (Exception ex)
            {
                //btnSend.Content = "Failed";
                MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                //btnSend.Content = "Send Again";
            }
        });

    }

目前我只是试图通过从表单上的文本框中获取数据来发送异步消息,它给了我

“调用线程无法访问此对象,因为不同的线程拥有它” 因为我是这类编程的新手,需要帮助。

PS。在上述问题之后,我将不得不使用以下方法从 DataGridView 中一一获取值并异步发送消息。请告诉我如何使用循环。 谢谢

            int i = dgvResults.SelectedIndex;
            DataRowView v = (DataRowView)dgvResults.Items[i];

            sIDCardNum = (string)v[0];
            Name = (string)v[1];
            Nmbr = (string)v[3];
            Msg = (string)v[4];

【问题讨论】:

    标签: wpf asynchronous sms async-await task


    【解决方案1】:

    您不能从另一个线程访问 UI 控件,唯一允许的线程是​​ UI 线程,要解决这个问题,您有两个解决方案,或者在每次使用这样的 UI 元素时使用 Dispatcher BeginInvoke:

        ...
     srprt.Write("AT+CMGF=1\r");
     Thread.Sleep(1000);
     Application.Current.Dispatcher.BeginInvoke(new Action(async () =>
     {
        srprt.Write("AT+CMGS=\"" + tbNmber.Text + "\"\r\r");
     }));
    
     Thread.Sleep(1000);
     Application.Current.Dispatcher.BeginInvoke(new Action(async () =>
     {
        srprt.Write(tbMessage.Text + "\x1A");
     }));
          ...
    

    或者不要从该异步方法访问这些控件并将所需的参数传递给它

    private Task sendSmsFunc(string phoneNumber,string message)
    

    更新

    关于如何循环遍历 GridView 项目列表的第二个问题,最佳和优雅的解决方案如下:

    -定义一个合适的模型来保存每一行的信息让我们说一个班级人:

    public class Person
    {
        public String Name { get; set; }
        public String PhoneNumber { get; set; }
        public String Message { get; set; }
    }
    

    -在您的窗口代码隐藏(或 ViewModel)中,首先实现 INotifyPropertyChanged 接口(这是一种在每次更改属性时通知 UI 更新的方法)并创建该模型的集合:

       public partial class MainWindow : Window,INotifyPropertyChanged
    {
        private ObservableCollection<Person> _peopleCollection;
        public ObservableCollection<Person> PeopleCollection
        {
            get { return _peopleCollection; }
            set
            {
                if (Equals(value, _peopleCollection)) return;
                _peopleCollection = value;
                OnPropertyChanged();
            }
        }
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;
            PeopleCollection = new ObservableCollection<Person>()
            {
                new Person(){Name = "Person1" ,PhoneNumber = "num1"},
                new Person(){Name = "Person2" ,PhoneNumber = "num2"}
            };
    
        }
        public event PropertyChangedEventHandler PropertyChanged;
    
        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    
     }
    }
    

    -在 Xaml 中定义你的 UI:

      <ListView ItemsSource="{Binding PeopleCollection}">
            <ListView.View>
                <GridView>
                    <GridView.Columns>
                        <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"/>
                        <GridViewColumn Header="Number" DisplayMemberBinding="{Binding PhoneNumber}"/>
                        <GridViewColumn Header="Message" DisplayMemberBinding="{Binding Message}"/>
                    </GridView.Columns>
                </GridView>
            </ListView.View>           
        </ListView>
        <Button VerticalAlignment="Bottom" Content="Loop" Click="ButtonBase_OnClick"></Button>
    

    -循环遍历 GridView 项目你需要做的就是循环遍历 ObservableCollection

    private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
            foreach (var person in PeopleCollection)
            {
                await sendSmsFunc(person.PhoneNumber, person.Message);
            }
        }
    

    Ps:别忘了设置DataContext

    this.DataContext = this;
    

    【讨论】:

    • 非常感谢。使用了第二个选项。我认为它更简单。你现在能帮我解决第二个问题吗?
    • 检查更新...我希望这对你来说已经足够详细了
    猜你喜欢
    • 2017-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多