我正在尝试构建一个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; }
}
}
}
答案 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)的消息因此,在您的情况下,您将拥有以下工作流程:
您可以查看以下示例。例如,Xamarin平台实现了一个消息中心&#39;类:
Xamarin MessaginCenter implementation documentation
Another C# implementation example 1
告诉我它是否清楚......