Я пытаюсь создать приложение UWP в C#, которое может управлять моим освещением в моем доме. Я могу получить данные с сервера и создать объекты лампы для каждой отдельной лампы. Эти объекты лампы затем помещаются в ObservableCollection
в начале приложения. Этот ObservableCollection
привязан к GridView
с DataTemplate
. Когда приложение запустилось, я вижу свои огни с правильными данными. Затем я повторно загружаю данные, чтобы проверять, менялось ли какое-либо свойство лампы каждые 500 мс. Я ясно вижу, что свойства объекта обновлены успешно, но связанные данные не распознают это изменение. Так что UI тоже не меняется. Я попытался использовать класс NotifyPropertyChange в классе Lamp, но это тоже ничего не дало.
После множества проб и ошибок я обнаружил, что пользовательский интерфейс изменяется только тогда, когда я добавляю, удаляю или заменяю объект в 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 просто анализирует строку и устанавливает свойства 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# код обновления
Edit
Я попытался реализовать INotifyPropertyChanged в своем классе лампы, как описано в документации Microsoft. Однако, похоже, это ничего не делает. Я также попытался передать имя в функции NotifyPropertyChanged()
, но это сделало мое приложение только sh.
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();
}
}
}
}
}