我使用observable collection来修改一个继承自INotifyPropertyChange
然而,当我更改文本框颜色时,它不会更改属性,PropertyChanged
保持为空并且不会触发。在第一次更改时,它不是null。但在第一次更改后,它始终为空。
附上我的代码:
namespace COMSimulator
{
[XmlRoot("SerialPortsColors")]
public class SerialPortsColors: ObservableCollection< COM>
{
}
public class COM : INotifyPropertyChanged
{
private string name;
private string color;
[XmlAttribute("Name")]
public string Name
{
get
{
return name;
}
set
{
name = value;
OnProperyChanged(name);
}
}
[XmlAttribute("Color")]
public string Color
{
get
{
return color;
}
set
{
OnProperyChanged(value);
color = value;
}
}
public COM()
{
name = "";
color = "";
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnProperyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
窗口代码隐藏:
public partial class colorPickerWindow : Window
{
private SerialPortsColorReadWriteXML _SerialPortsColorReadWriteXML;
public colorPickerWindow()
{
InitializeComponent();
updateSerialPorts();
_SerialPortsColorReadWriteXML = new SerialPortsColorReadWriteXML();
string err = _SerialPortsColorReadWriteXML.ReadXML();
if (err != "")
{
MessageBox.Show(err);
return;
}
LBSerialAndColors.ItemsSource = _SerialPortsColorReadWriteXML.LSerialPortsColors;
}
private void updateSerialPorts()
{
string [] PortName = System.IO.Ports.SerialPort.GetPortNames();
for (int i = 0; i <PortName.Length; i++)
{
CB_SelecComPort.Items.Add(PortName[i]);
}
}
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
string err=""; //case there is an error
string COM_TEXT = CB_SelecComPort.Text;
MySerialPort.FuncConverstion.checkComName(ref COM_TEXT,ref err);
if (_colorPicker.SelectedColor == null)
{
MessageBox.Show("Please Select a color");
return;
}
if (err!="")
{
MessageBox.Show(err);
return;
}
for (int i = 0; i < _SerialPortsColorReadWriteXML.LSerialPortsColors.Count; i++)
{
if (_SerialPortsColorReadWriteXML.LSerialPortsColors[i].Name == CB_SelecComPort.Text)
{
_SerialPortsColorReadWriteXML.LSerialPortsColors[i].Color = _colorPicker.SelectedColor.Value.R.ToString("X2") + _colorPicker.SelectedColor.Value.G.ToString("X2") + _colorPicker.SelectedColor.Value.B.ToString("X2") + _colorPicker.SelectedColor.Value.A.ToString("X2"); //R G B A
_SerialPortsColorReadWriteXML.WriteXML();
_SerialPortsColorReadWriteXML.ReadXML();
MessageBox.Show("Serial Port and Color has been updated");
return;
}
}
COM NewCom = new COM ();
NewCom.Color = _colorPicker.SelectedColor.Value.R.ToString("X2") + _colorPicker.SelectedColor.Value.G.ToString("X2") + _colorPicker.SelectedColor.Value.B.ToString("X2") + _colorPicker.SelectedColor.Value.A.ToString("X2"); //R G B A
NewCom.Name = CB_SelecComPort.Text;
_SerialPortsColorReadWriteXML.LSerialPortsColors.Add(NewCom);
_SerialPortsColorReadWriteXML.WriteXML();
_SerialPortsColorReadWriteXML.ReadXML();
MessageBox.Show("Serial Port and Color has been updated");
}
}
public class COMColorConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string Color_bytes = value.ToString();
string R = Color_bytes[0].ToString() + Color_bytes[1].ToString();
string G = Color_bytes[2].ToString() + Color_bytes[3].ToString();
string B = Color_bytes[4].ToString() + Color_bytes[5].ToString();
string A = Color_bytes[6].ToString() + Color_bytes[7].ToString();
Color _Color = new Color();
_Color.R = byte.Parse(R,System.Globalization.NumberStyles.AllowHexSpecifier);
_Color.G = byte.Parse(G, System.Globalization.NumberStyles.AllowHexSpecifier);
_Color.B = byte.Parse(B, System.Globalization.NumberStyles.AllowHexSpecifier);
_Color.A = byte.Parse(A, System.Globalization.NumberStyles.AllowHexSpecifier);
SolidColorBrush SCB = new SolidColorBrush(_Color);
return SCB;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class SerialPortsColorReadWriteXML:
{
private SerialPortsColors _LSerialPortsColors;
public SerialPortsColorReadWriteXML()
{
_LSerialPortsColors = new SerialPortsColors();
}
public SerialPortsColors LSerialPortsColors
{
get
{
return _LSerialPortsColors;
}
set
{
_LSerialPortsColors = value;
}
}
private string path = "SerialPortsColors.xml";
/// <summary>
/// read the serial ports color XML
/// </summary>
/// <returns>In Case of an error return the error</returns>
public string ReadXML()
{
XmlSerializer serializer = new XmlSerializer(typeof(SerialPortsColors));
try
{
using (XmlReader reader = XmlReader.Create(path))
{
LSerialPortsColors = (SerialPortsColors)serializer.Deserialize(reader);
}
return "";
}
catch (Exception )
{
return "There is an issue with the path of the Serial Ports Color XML";
}
}
public string WriteXML()
{
XmlSerializer serializer = new XmlSerializer(typeof(SerialPortsColors));
try
{
XmlWriterSettings xws = new XmlWriterSettings();
xws.Indent = true;
using (XmlWriter writer = XmlWriter.Create(path, xws))
{
serializer.Serialize(writer, LSerialPortsColors);
}
return "";
}
catch
{
return "There is an issue Creating a new XML File";
}
}
}
XAML:
<Window x:Class="COMSimulator.colorPickerWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:Converters="clr-namespace:COMSimulator"
Title="colorPickerWindow" Height="400" Width="300" WindowState="Normal" WindowStartupLocation="CenterScreen" ResizeMode="NoResize">
<Window.Resources>
<Converters:COMColorConverter x:Key="COMColorConverter" />
</Window.Resources>
<Grid>
<Grid.Resources>
<DataTemplate x:Key="COMColorTemplate">
<Border BorderBrush="Black" BorderThickness="1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="1*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged }" HorizontalAlignment="Left" VerticalAlignment="Center" Width="100" />
<TextBlock Grid.Column="1" HorizontalAlignment="Left" Width="150" Background="{Binding UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, Path=Color, Converter={StaticResource COMColorConverter}}" ></TextBlock>
</Grid>
</Border>
</DataTemplate>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="120"/>
<RowDefinition Height="3"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" Grid.Column="0" BorderThickness="1" BorderBrush="Black">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*"></RowDefinition>
<RowDefinition Height="10"></RowDefinition>
<RowDefinition Height="1*"></RowDefinition>
<RowDefinition Height="10"></RowDefinition>
<RowDefinition Height="1*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="5"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Content="Select COM Port:" VerticalAlignment="Center" HorizontalAlignment="Center"></Label>
<ComboBox x:Name="CB_SelecComPort" Grid.Column="1" Grid.Row="0" VerticalAlignment="Center"></ComboBox>
<Label Content="Select Color:" VerticalAlignment="Center" Grid.Row="2" Grid.Column="0" HorizontalAlignment="Center"></Label>
<xctk:ColorPicker x:Name="_colorPicker" Grid.Column="1" Grid.Row="2" VerticalAlignment="Center" />
<Button x:Name="btnAdd" Content="Add Or Edit" Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="150" Click="btnAdd_Click"></Button>
</Grid>
</Border>
<Border Grid.Row="2" Grid.Column="0" BorderThickness="1" BorderBrush="Black" >
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<ListBox x:Name="LBSerialAndColors" ItemTemplate="{DynamicResource COMColorTemplate}" >
</ListBox>
</ScrollViewer>
</Border>
</Grid>
</Window>
答案 0 :(得分:2)
在更改颜色之前,您正在通知UI颜色已更改。试试这个:
public string Color
{
get
{
return color;
}
set
{
color = value;
OnProperyChanged("Color");
}
}
答案 1 :(得分:1)
您应该将属性的名称传递给OnPropertyChanged
方法,即OnProperyChanged("Name")
而不是OnProperyChanged(name)
:
public string Name
{
get
{
return name;
}
set
{
name = value;
OnProperyChanged("Name");
}
}
[XmlAttribute("Color")]
public string Color
{
get
{
return color;
}
set
{
color = value;
OnProperyChanged("Color");
}
}
还要确保在举起PropertyChanged
事件之前设置支持字段。
编辑:如@john所评论,您可以在C#6或更高版本中使用nameof
运算符:
OnProperyChanged(nameof(Color));
编辑2:
有点不清楚你期望发生什么,但如果你想设置Name
中显示的实际项目的Color
或ListBox
属性,你应该迭代这些:< / p>
foreach(var item in LBSerialAndColors.Items.OfType<COM>())
{
if (item.Name == CB_SelecComPort.Text)
{
item.Color = _colorPicker.SelectedColor.Value.R.ToString("X2") + _colorPicker.SelectedColor.Value.G.ToString("X2") + _colorPicker.SelectedColor.Value.B.ToString("X2") + _colorPicker.SelectedColor.Value.A.ToString("X2"); //R G B A
MessageBox.Show("Serial Port and Color has been updated");
return;
}
}
如果每次调用属性时_SerialPortsColorReadWriteXML.LSerialPortsColors
都返回新对象,则迭代这些对象是没有意义的。
答案 2 :(得分:0)
问题出在我已经重新编写XML的类中,这里没有继承SerialPortsColorReadWriteXML:INotifyPropertyChanged
function doGet() {
var t = HtmlService.createTemplateFromFile('index.html');
var ss = SpreadsheetApp.openById('sheet_ID');
var lrN = ss.getSheetByName('NCMR').getLastRow();
t.statArray = ss.getSheetByName('NCMR').getRange('Z3:Z'+lrN+'').getValues();
return t.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME);
}