从MainWindow更新第二个窗口中的列表

时间:2018-05-31 23:07:10

标签: c# wpf visual-studio mvvm data-binding

我正在尝试构建一个WPF应用程序,通过从串行端口读取信号,在第二台显示器上显示操作激光器列表。我遇到的麻烦是,在实例化时,我将List作为第二个窗口类的构造函数的参数传递,但是当有一个更改(一些激光器关闭,其他激光器打开)时,MainWindow中的列表会更新,但是列表未在第二个窗口中更新。当我尝试在第二个窗口上调用一个函数或尝试从MainWindow更新第二个Windows列表时,我得到了线程异常。我也一直在使用MVVM,DataContext等阅读类似的问题和解决方案,但无法理解它如何解决我的问题。

如何让我的Window1(第二个窗口)更新其List并因此更新其DataGrid?

以下是不同文件的代码:

MainWindow.xaml

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="Laser Control " Height="766" ResizeMode="CanMinimize" Cursor="Arrow" Width="1071">

    <Grid>
        <DockPanel 
            HorizontalAlignment="Stretch" 
            LastChildFill="False" 
            VerticalAlignment="Stretch" 
            Background="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}">

            <Grid Height="50" DockPanel.Dock="Top" Grid.IsSharedSizeScope="True" HorizontalAlignment="Stretch">
                <Grid.ColumnDefinitions >
                    <ColumnDefinition SharedSizeGroup="top" Width="300"/>
                    <ColumnDefinition SharedSizeGroup="top"/>
                    <ColumnDefinition SharedSizeGroup="top"/>
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="Calibri" FontSize="20" FontWeight="Bold" Foreground="#FFF3F1F1"><Run Text="Marciante Lab "/><Run Text="Laser "/><Run Text="Control"/></TextBlock>
            </Grid>

            <Grid 
                DockPanel.Dock="Bottom"
                Background="Beige"
                Height="50">

            </Grid>

            <Grid 
                DockPanel.Dock="Left"
                VerticalAlignment="Stretch"
                Width="200" 
                Background="{DynamicResource {x:Static SystemColors.ScrollBarBrushKey}}">
                <Button Content="Show Door Display"                         
                        HorizontalAlignment="Left" 
                        VerticalAlignment="Top"
                        Margin="57,54,0,0"   
                        Width="120" 
                        Click="showDoorDisplay" 
                        Height="23"/>

                <Button x:Name="Connect"    
                        Content="Connect to Arduino"    
                        HorizontalAlignment="Left"                      
                        VerticalAlignment="Top" 
                        Width="120"
                        Height="23"
                        Click="connectArduino"  
                        Margin="57,265,0,0"/>

                <Button x:Name="Disconnect" 
                        Content="Disconnect Arduino"    
                        HorizontalAlignment="Left"
                        VerticalAlignment="Top" 
                        Width="120"
                        Height="23" 
                        Click="disconnectArduino" Margin="57,293,0,0"/>

                <TextBlock  x:Name="ArduinoStatus"
                            HorizontalAlignment="Left"
                            VerticalAlignment="Top"
                            TextWrapping="Wrap"
                            Text="Disconnected"
                            FontSize="20"
                            TextAlignment="Center"
                            Height="30"
                            Width="120" Margin="57,343,0,0"/>

                <ComboBox   x:Name="dropdownList"
                            HorizontalAlignment="Left"
                            VerticalAlignment="Top"
                            Margin="57,224,0,0"  
                            Width="120" 
                            SelectionChanged="ComboBox_SelectionChanged"
                            ItemsSource="{Binding ports}"
                            >



                </ComboBox>

            </Grid>

            <Grid
                DockPanel.Dock="Right"
                Width="200"
                Background="Black">


            </Grid>



            <ListView>


            </ListView>
            <Button Content="" Height="637" VerticalAlignment="Top" Width="75"/>

        </DockPanel>
    </Grid>


</Window>

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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.IO.Ports;
using System.ComponentModel;
namespace WpfApp1
{

    using Screen = System.Windows.Forms.Screen;


    /// <summary>
    /// Window1.xaml etkileşim mantığı
    /// </summary>
    public partial class MainWindow : Window
    {

        SerialPort sp = new SerialPort();
        List<Laser> laserList = new List<Laser> { };
        Window1 doorPanel;


        string[] ports = SerialPort.GetPortNames();

        public MainWindow(){
            InitializeComponent();

            foreach (string s in System.IO.Ports.SerialPort.GetPortNames())
            {
                dropdownList.Items.Add(s);
            }
        }

        private void showDoorDisplay(object sender, RoutedEventArgs e){

            doorPanel = new Window1(laserList) {
                DataContext = this
            };
            int secondScreen = 1;
            ShowOnMonitor(secondScreen, doorPanel);
            //laserList.Add(new Laser() { Name = "Laser" + (14), Wavelength = 520, Power = 1000, Temperature = 27 });

        }

        private void ShowOnMonitor(int monitor, Window window){

            var screen = ScreenHandler.GetScreen(monitor);
            //var currentScreen = ScreenHandler.GetCurrentScreen(this);

            window.WindowState = WindowState.Normal;
            window.Left = screen.WorkingArea.Left;
            window.Top = screen.WorkingArea.Top;
            window.Width = screen.WorkingArea.Width;
            window.Height = screen.WorkingArea.Height;
            window.Loaded += Window_Loaded;
            window.DataContext = laserList;
            window.Show();
        }

            /*You can use this event for all the Windows*/
        private void Window_Loaded(object sender, RoutedEventArgs e){
            var senderWindow = sender as Window;
            senderWindow.WindowState = WindowState.Maximized;
        }

        public static class ScreenHandler{

            public static Screen GetCurrentScreen(Window window){

                var parentArea = new System.Drawing.Rectangle((int)window.Left, (int)window.Top, (int)window.Width, (int)window.Height);
                return Screen.FromRectangle(parentArea);
            }

            public static Screen GetScreen(int requestedScreen){

                var screens = Screen.AllScreens;
                var mainScreen = 0;
                if (screens.Length > 1 && mainScreen < screens.Length)
                {
                    return screens[requestedScreen];
                }
                MessageBox.Show("Second Screen not Found, Check Connection");
                return screens[0];
            }
        }

        private void connectArduino(object sender, RoutedEventArgs e){

            //TODO: gotta find the comportno
            try
            {
                //ports = SerialPort.GetPortNames();

                String portName = dropdownList.SelectedItem.ToString();
                sp.PortName = portName;
                sp.BaudRate = 9600;
                sp.Open();
                System.Diagnostics.Debug.WriteLine("read serial:");
                //System.Diagnostics.Debug.WriteLine(sp.ReadLine());
                sp.DataReceived += new SerialDataReceivedEventHandler(serialDR);

                ArduinoStatus.Text = "Connected";
            }

            catch(Exception)
            {
                MessageBox.Show("Please give a valid port number or check your connection");
            }

        }

        void serialDR(object sender, SerialDataReceivedEventArgs e)
        {

            laserList.Clear();
            string message = sp.ReadLine();
            int temp;
            bool[] laserpins=new bool[16];
            for (int i=0; i<4; i++)
            {
                temp= int.Parse((message[3 - i].ToString()), System.Globalization.NumberStyles.HexNumber);
                laserpins[0+4*i]= (temp % 2==1);
                temp = temp / 2;
                laserpins[1 + 4 * i] = (temp % 2 == 1);
                temp = temp / 2;
                laserpins[2 + 4 * i] = (temp % 2 == 1);
                temp = temp / 2;
                laserpins[3 + 4 * i] = (temp % 2 == 1);

            }
           // ushort message2 = Convert.ToUInt16(message);

            //System.Diagnostics.Debug.WriteLine("Printing Serial Message: ");
            System.Diagnostics.Debug.WriteLine(message);

            if(laserpins[0] == true){laserList.Add(new Laser() { Name = "Laser" + (1), Wavelength = 520, Power = 1000, Temperature = 27 });}
            if(laserpins[1] == true) { laserList.Add(new Laser() { Name = "Laser" + (2), Wavelength = 520, Power = 1000, Temperature = 27 });}
            if (laserpins[2] == true) { laserList.Add(new Laser() { Name = "Laser" + (3), Wavelength = 520, Power = 1000, Temperature = 27 }); }
            if (laserpins[3] == true) { laserList.Add(new Laser() { Name = "Laser" + (4), Wavelength = 520, Power = 1000, Temperature = 27 }); }
            if (laserpins[4] == true) { laserList.Add(new Laser() { Name = "Laser" + (5), Wavelength = 520, Power = 1000, Temperature = 27 }); }
            if (laserpins[5] == true) { laserList.Add(new Laser() { Name = "Laser" + (6), Wavelength = 520, Power = 1000, Temperature = 27 }); }
            if (laserpins[6] == true) { laserList.Add(new Laser() { Name = "Laser" + (7), Wavelength = 520, Power = 1000, Temperature = 27 }); }
            if (laserpins[7] == true) { laserList.Add(new Laser() { Name = "Laser" + (8), Wavelength = 520, Power = 1000, Temperature = 27 }); }
            if (laserpins[8] == true) { laserList.Add(new Laser() { Name = "Laser" + (9), Wavelength = 520, Power = 1000, Temperature = 27 }); }
            if (laserpins[9] == true) { laserList.Add(new Laser() { Name = "Laser" + (10), Wavelength = 520, Power = 1000, Temperature = 27 }); }
            if (laserpins[10] == true) { laserList.Add(new Laser() { Name = "Laser" + (11), Wavelength = 520, Power = 1000, Temperature = 27 }); }
            if (laserpins[11] == true) { laserList.Add(new Laser() { Name = "Laser" + (12), Wavelength = 520, Power = 1000, Temperature = 27 }); }
            if (laserpins[12] == true) { laserList.Add(new Laser() { Name = "Laser" + (13), Wavelength = 520, Power = 1000, Temperature = 27 }); }
            if (laserpins[13] == true) { laserList.Add(new Laser() { Name = "Laser" + (14), Wavelength = 520, Power = 1000, Temperature = 27 }); }
            if (laserpins[14] == true) { laserList.Add(new Laser() { Name = "Laser" + (15), Wavelength = 520, Power = 1000, Temperature = 27 }); }
            if (laserpins[15] == true) { laserList.Add(new Laser() { Name = "Laser" + (16), Wavelength = 520, Power = 1000, Temperature = 27 }); }

            /*
            Application.Current.Dispatcher.Invoke((Action)delegate {
                //doorPanel.UpdateLayout();
                //doorPanel.Close();
                // doorPanel = new Window1(laserList);
                //int secondScreen = 1;
                // ShowOnMonitor(secondScreen, doorPanel);
            });
            */        

        }

        private void disconnectArduino(object sender, RoutedEventArgs e)
        {

            try {
                laserList.Add(new Laser() { Name = "Laser" + (15), Wavelength = 520, Power = 1000, Temperature = 27 });
                sp.Close();
                ArduinoStatus.Text = "Disconnected";
            }

            catch (Exception)
            {
                MessageBox.Show("First Connect and then disconnect");
            }

        }

        private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {

        }
    }

    public class myViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    }


}

Window1.xaml

    <Window x:Class="WpfApp1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="Door Display" Height="768" Width="1024"
        ResizeMode="NoResize"
        WindowState="Maximized">

    <Grid>

        <Grid.RowDefinitions>
            <RowDefinition Height="250"/>
            <RowDefinition Height="250"/>
            <RowDefinition Height="676*"/>
        </Grid.RowDefinitions>

        <Border 
            Grid.Row="0"
            VerticalAlignment="Stretch"
            HorizontalAlignment="Stretch"
            Background="Red">

            <Border.Triggers>
                <EventTrigger RoutedEvent="Window.Loaded">
                    <BeginStoryboard>
                        <Storyboard>


                                <DoubleAnimationUsingKeyFrames
                                    Storyboard.TargetProperty="Opacity"


                                    Duration="0:0:.6"


                                    RepeatBehavior="Forever">
                                    <DiscreteDoubleKeyFrame Value="0.0" KeyTime="0:0:.3"/>
                                    <DiscreteDoubleKeyFrame Value="1.0" KeyTime="0:0:.6"/>

                                </DoubleAnimationUsingKeyFrames>



                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Border.Triggers>


        </Border>
        <TextBlock
                Name="IRTextBlock"
                HorizontalAlignment="Stretch"
                VerticalAlignment="Center"
                Grid.Row="0"
                Text="Infrared" 
                FontSize="120"
                TextAlignment="Center">


        </TextBlock>

        <Border 
            Grid.Row="1"
            VerticalAlignment="Stretch"
            HorizontalAlignment="Stretch"
            Background="Green">

            <Border.Triggers>
                <EventTrigger RoutedEvent="Window.Loaded">
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimationUsingKeyFrames
                                    Storyboard.TargetProperty="Opacity"
                                    BeginTime="0:0:0" 

                                    Duration="0:0:.6"


                                    RepeatBehavior="Forever">
                                <DiscreteDoubleKeyFrame Value="0.0" KeyTime="0:0:.3"/>
                                <DiscreteDoubleKeyFrame Value="1.0" KeyTime="0:0:.6"/>

                            </DoubleAnimationUsingKeyFrames>

                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Border.Triggers>
        </Border>

        <TextBlock
                Name="VisTextBlock"
                HorizontalAlignment="Stretch"
                VerticalAlignment="Center"
                Grid.Row="1"
                Text="Visible" 
                FontSize="80"

                TextAlignment="Center"/>


        <DataGrid 

            ColumnWidth="*"
            Name="LaserDataGrid"
            AutoGenerateColumns="True"
            SelectionUnit="FullRow"
            Grid.Row="2"
            IsReadOnly="True"
            CanUserAddRows="True"
            CanUserDeleteRows="True"
            SourceUpdated="LaserDataGrid_SourceUpdated"

            >
        </DataGrid>



    </Grid>

</Window>

Window1.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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.Shapes;


namespace WpfApp1
{
    /// <summary>
    /// Window1.xaml etkileşim mantığı
    /// </summary>
    public partial class Window1 : Window{

        List<Laser> laserList;


        public Window1(List<Laser> laserList)
        {
            InitializeComponent();

            this.laserList = laserList;
            this.LaserDataGrid.ItemsSource = laserList;
            this.LaserDataGrid.FontSize = 20;
            this.DataContextChanged += new DependencyPropertyChangedEventHandler(contextChanged);

            this.Show();
        }

        private void contextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            this.laserList = laserList;
            this.LaserDataGrid.ItemsSource = laserList;

        }

        private void Window_Loaded(object sender, RoutedEventArgs e){
            MessageBox.Show("Laser is Active","System Active Warning");  
        }


    }

    public class Laser {

        private string laserName;
        public string Name{
            get { return laserName; }
            set { laserName = value; }
        }

        private double wavelength;
        public double Wavelength{
            get { return wavelength; }
            set { wavelength = value; }
        }

        private double power;
        public double Power{
            get { return power; }
            set { power = value; }
        }

        private double temperature;
        public double Temperature{
            get { return temperature;
            }
            set { temperature = value; }
        }
    }

}

1 个答案:

答案 0 :(得分:1)

我不了解/了解您项目的所有技术细节,但针对您的具体问题(关于在两个窗口之间进行更改),您可以使用一种&#39; Messaging&#39 ;图案

目标是建立一个界面(一个类)来管理消息&#39;来自您应用的不同图层/组件。

此界面将包含3个主要方法

  • 一种Publish<T>(object sender, T message)方法,可让课程向所有听众发送讯息&#39;
  • 一种Subscribe<T>(object listener, Action<T> listenerAction)方法,允许特定类侦听特定的消息类型。
  • Unsubscribe<T>(object listener)停止侦听特定类型(T)的消息

因此,在您的情况下,您将拥有以下工作流程

  • Window2 - &gt; MessagingCenter.Subscribe(...)
  • 然后Window1 - &gt; MessagingCenter.Publish(...)
  • Window2 - &gt; MessagingCenter.Unsubscribe(...)

您可以查看以下示例。例如,Xamarin平台实现了一个消息中心&#39;类:

Xamarin MessaginCenter implementation documentation

Another C# implementation example 1

告诉我它是否清楚......