我正在尝试用C#创建一个UWP应用程序,以控制家里的灯光。我能够从服务器获取数据并为每个单独的灯创建灯对象。然后将这些灯对象放置在应用程序开头的ObservableCollection
中。该ObservableCollection
与GridView
绑定到DataTemplate
。当应用启动时,我可以看到带有正确数据的灯。然后,我重新获取数据以检查是否每500毫秒更改任何灯泡属性。我可以清楚地看到对象属性已成功更新,但是绑定数据无法识别此更改。因此,UI也不更改。我尝试在Lamp类中使用NotifyPropertyChange,但这也没有执行。
经过大量的试验和错误后,我发现ui仅在我添加,删除或替换ObservableCollection
中的对象时才更改,但是替换对我来说并不是一个实际的选择,因为它会导致很多不稳定并且看起来不像是必须解决此问题的方法。
<GridView ItemsSource="{x:Bind LampCollection}" Margin="10 0" HorizontalAlignment="Center">
<GridView.ItemTemplate>
<DataTemplate x:DataType="local:Lamp">
<Border BorderBrush="#555555" BorderThickness="1" CornerRadius="8" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="10" >
<Grid Width="300" Height="200">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Image Grid.Row="0" Grid.Column="0" Source="{x:Bind ImageUri, Mode=OneWay}" Width="80" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal" >
<TextBlock Name="txt" VerticalAlignment="Bottom" FontSize="20" FontWeight="Bold" Margin="10,0,0,20" Text="{x:Bind Name, Mode=OneTime}"/>
<TextBlock Name="status" VerticalAlignment="Bottom" FontSize="11" FontWeight="Bold" Margin="10,0,0,20" Text="{x:Bind Status, Mode=OneWay}"/>
</StackPanel>
<Rectangle Grid.Row="1" Grid.Column="0" Visibility="{x:Bind ColorLamp}" Width="50" Height="50" Fill="Maroon"/>
<Slider Visibility="{x:Bind Dimmable}" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="10,0,10,0" Value="{x:Bind Brightness, Mode=TwoWay}"/>
</Grid>
</Border>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
Xaml代码
lamp.SetStatus函数仅解析字符串并设置绑定到UI的属性Brightness和Status。
foreach (Lamp lamp in LampCollection) {
string response = await GetAsync(UrlString + lamp.IDX.ToString());
dynamic json = JsonConvert.DeserializeObject(response);
if (json.status == "OK") {
lamp.SetStatus(json.result[0].Status.ToString());
}
}
C#更新代码
修改
我尝试按照Microsoft文档中的描述在我的灯类中实现INotifyPropertyChanged。它似乎什么也没做。我还尝试在NotifyPropertyChanged()
函数中传递名称,但这只会使我的应用崩溃。
class Lamp : INotifyPropertyChanged {
public uint IDX { get; internal set; }
public string Name { get; internal set; }
public bool Status { get; internal set; }
public string ImageUri { get; internal set; }
public bool Dimmable { get; internal set; }
public bool ColorLamp { get; internal set; }
public uint Brightness { get; set; }
public float[] Color { get; set; }
public Lamp(uint idx, string name, string status, bool dimmable, bool colorLamp) {
IDX = idx;
Name = name;
Color = new float[3];
Dimmable = dimmable;
ColorLamp = colorLamp;
if (status == "Off") {
ImageUri = "Images/lamp-off.svg";
Status = false;
} else {
ImageUri = "Images/lamp-on.svg";
Status = true;
if(dimmable) {
Brightness = uint.Parse(Regex.Match(status, @"\d+").Value, NumberFormatInfo.InvariantInfo);
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "") {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public void Switch(bool status) {
Status = status;
if(status) ImageUri = "Images/lamp-on.svg";
else ImageUri = "Images/lamp-off.svg";
NotifyPropertyChanged();
}
public void SetColor(float r, float g, float b) { if (ColorLamp) { Color[0] = r; Color[1] = g; Color[2] = b; } }
public void SetStatus(string status) {
if (status == "Off") {
if (Status) {
ImageUri = "Images/lamp-off.svg";
Status = false;
if (Dimmable) Brightness = 0;
Debug.WriteLine(Name + "(" + IDX + ") has turned off");
NotifyPropertyChanged();
}
} else {
if (Dimmable) {
uint _tmpBright = uint.Parse(Regex.Match(status, @"\d+").Value, NumberFormatInfo.InvariantInfo);
if(!Status || Brightness != _tmpBright) {
ImageUri = "Images/lamp-on.svg";
Status = true;
Brightness = _tmpBright;
Debug.WriteLine(Name + "(" + IDX + ") has turned on or changed brighntess");
NotifyPropertyChanged();
}
} else {
if (!Status) {
ImageUri = "Images/lamp-on.svg";
Status = true;
Debug.WriteLine(Name + "(" + IDX + ") has turned on");
NotifyPropertyChanged();
}
}
}
}
}
答案 0 :(得分:0)
基于代码段,您在SetStatus()方法中调用了 NotifyPropertyChanged ()方法,并且 CallerMemberName 允许您获取调用者的方法或属性名称对于该方法,如果不将任何propertyName传递给NotifyPropertyChanged()方法,它将自动获取方法名称为 SetStatus 。但是,没有与SetStatus绑定的UI,因此该UI将不会更新。如果要在这种情况下更新与Status和Brightness属性绑定的UI,可以将这两个属性名称传递给NotifyPropertyChanged()方法,例如:
public void SetStatus(string status)
{
if (status == "Off")
{
if (Status)
{
ImageUri = "Assets/2.jpg";
Status = false;
if (Dimmable) Brightness = 0;
Debug.WriteLine(Name + "(" + IDX + ") has turned off");
NotifyPropertyChanged("Status");
NotifyPropertyChanged("Brightness");
}
}
......
}
但是,每次在SetStatus()方法或Lamp类中的其他方法中更改Status和Brightness属性的值时,都需要调用NotifyPropertyChanged(“ xxx”)方法,有点复杂。您可以声明一个私有变量并覆盖get和set方法,在set方法中调用NotifyPropertyChanged()方法,每次为属性设置一个新值时,它将进入set方法,然后通知UI更新。以状态和亮度为例:
public class Lamp : INotifyPropertyChanged
{
private bool status { get; set; }
private uint brightness { get; set; }
public bool Status {
get {
return status;
}
set {
status = value;
NotifyPropertyChanged();
}
}
public uint Brightness
{
get
{
return brightness;
}
set
{
brightness = value;
NotifyPropertyChanged();
}
}
// The same behavior to the following properties
public uint IDX { get; internal set; }
public string Name { get; internal set; }
public string ImageUri { get; internal set; }
public bool Dimmable { get; internal set; }
public bool ColorLamp { get; internal set; }
public float[] Color { get; set; }
public Lamp(uint idx, string name, string status, bool dimmable, bool colorLamp)
{
IDX = idx;
Name = name;
Color = new float[3];
Dimmable = dimmable;
ColorLamp = colorLamp;
if (status == "Off")
{
ImageUri = "Assets/2.jpg";
Status = false;
}
else
{
ImageUri = "Assets/3.jpg";
Status = true;
if (dimmable)
{
Brightness = uint.Parse(Regex.Match(status, @"\d+").Value, NumberFormatInfo.InvariantInfo);
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public void Switch(bool status)
{
Status = status;
if (status) ImageUri = "Assets/3.jpg";
else ImageUri = "Assets/2.jpg";
}
public void SetColor(float r, float g, float b) { if (ColorLamp) { Color[0] = r; Color[1] = g; Color[2] = b; } }
public void SetStatus(string status)
{
if (status == "Off")
{
if (Status)
{
ImageUri = "Assets/2.jpg";
Status = false;
if (Dimmable) Brightness = 0;
}
}
else
{
if (Dimmable)
{
uint _tmpBright = 30;
if (!Status || Brightness != _tmpBright)
{
ImageUri = "Assets/3.jpg";
Status = true;
Brightness = _tmpBright;
}
}
else
{
if (!Status)
{
ImageUri = "Assets/3.jpg";
Status = true;
}
}
}
}
}