属性 更改后模板 10 UI 未刷新

Template10 UI not refreshing after property changed

我正在使用模板 10 开发 UWP 应用程序,在 ViewModel 中更改 属性 后,我无法更新 UI。我尝试在模型中实现 Bindable 基础,但仍然无法正常工作。

XAML:

<Page.DataContext>
    <vm:RoomPageViewModel x:Name="ViewModel" />
</Page.DataContext>

<Grid x:Name="RoomProperties"
    RelativePanel.Below="pageHeader"
    RelativePanel.AlignLeftWithPanel="True">
    <Grid.ColumnDefinitions>
        <ColumnDefinition></ColumnDefinition>
        <ColumnDefinition></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition></RowDefinition>
        <RowDefinition></RowDefinition>
        <RowDefinition></RowDefinition>
    </Grid.RowDefinitions>
    <Image Grid.Column="0" Width="220" Height="220" Stretch="Fill" Source="{x:Bind ViewModel.Room.Image}"></Image>
    <TextBlock Grid.Column="1" FontSize="16" Text="{x:Bind ViewModel.Room.Name}"></TextBlock>
    <TextBlock Grid.Column="0" Grid.Row="1" FontSize="16" Text="Room Type: "></TextBlock>
    <TextBlock Grid.Column="1" Grid.Row="1" FontSize="16" Text="{x:Bind ViewModel.Room.Type}"></TextBlock>
    <TextBlock Grid.Column="0" Grid.Row="2" FontSize="16" Text="Room Number: "></TextBlock>
    <TextBlock Grid.Column="1" Grid.Row="2" FontSize="16" Text="{x:Bind ViewModel.Room.Number}"></TextBlock>
</Grid>
<ListView x:Name="SensorListView"
          ItemsSource="{x:Bind ViewModel.Room.Sensors}"
          IsEnabled="False"
          RelativePanel.Below="RoomProperties"
          RelativePanel.AlignLeftWithPanel="True">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="data:Sensor">
            <StackPanel HorizontalAlignment="Left">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition></ColumnDefinition>
                        <ColumnDefinition></ColumnDefinition>
                        <ColumnDefinition></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Column="0" FontSize="16" Text="{x:Bind Name}"></TextBlock>
                    <TextBlock Grid.Column="1" FontSize="16" Text="{x:Bind SensorValues[0].Value, Mode=TwoWay}"></TextBlock>
                    <TextBlock Grid.Column="2" FontSize="16" Text="{x:Bind Units}"></TextBlock>
                </Grid>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

视图模型:

public class RoomPageViewModel : ViewModelBase
{
    Template10.Services.SerializationService.ISerializationService _SerializationService;
    private FileIOHelper.FileIOHelper fileIOHelper = new FileIOHelper.FileIOHelper();
    private AppServiceConnection serialCommandService;

    // This method is called by the Set accessor of each property.
    // The CallerMemberName attribute that is applied to the optional propertyName
    // parameter causes the property name of the caller to be substituted as an argument.

    public RoomPageViewModel()
    {
        if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
        {
            Room = Room.CreateNewRoom();
        }
    }

    private Room room = Room.CreateNewRoom();
    public Room Room
    {
        get
        {
            return this.room;
        }

        set
        {
            Set(ref room, value);
        }
    }

    public void UpdateRoom()
    {
        foreach (var sensor in Room.Sensors)
        {
            var sensorValue = new SensorValue();
            sensorValue.Sensor = "R" + Room.Number + "D" + sensor.DeviceNumber + "S" + sensor.Type;
            ObservableCollection<SensorValue> newList = fileIOHelper.ReadFromFile(sensorValue).ToObservableCollection();
            SensorValue newSensorValue = newList.Last();
            sensor.SensorValues = new ObservableCollection<SensorValue> { newSensorValue };
        }
        foreach (var actuator in Room.Actuators)
        {
            var actuatorValue = ActuatorValue.CreateNewActuatorValue();
            actuatorValue.Actuator = "R" + Room.Number + "D" + actuator.DeviceNumber + "A" + actuator.Type;
            ObservableCollection<ActuatorValue> newList = fileIOHelper.ReadFromFile(actuatorValue).ToObservableCollection();
            ActuatorValue newActuatorValue = newList.Last();
            actuator.ActuatorValues = new ObservableCollection<ActuatorValue> { newActuatorValue };
        }
    }

    public async void RefreshButton_Click(object sender, object parameter)
    {
        Random rnd = new Random();
        Room = Room.CreateNewRoom(rnd.Next(1, 9));
        //UpdateRoom();
        await Task.CompletedTask;
    }

型号:

public class Room : BindableBase
{
    private string name;
    private string image;
    private string type;
    private int number; 

    public string Name
    {
        get
        {
            return name;
        }
        set
        {
            Set(ref name, value);
        }
    }

    public string Image
    {
        get
        {
            return image;
        }
        set
        {
            Set(ref image, value);
        }
    }

    public string Type
    {
        get
        {
            return type;
        }
        set
        {
            Set(ref type, value);
        }
    }

    public int Number
    {
        get
        {
            return number;
        }
        set
        {
            Set(ref number, value);
        }
    }

    private ObservableCollection<Sensor> sensors;

    private ObservableCollection<Actuator> actuators;

    public ObservableCollection<Sensor> Sensors
    {
        get
        {
            return sensors;
        }
        set
        {
            Set(ref sensors, value);
        }
    }

    public ObservableCollection<Actuator> Actuators
    {
        get
        {
            return actuators;
        }
        set
        {
            Set(ref actuators, value);
        }
    }

    public Room() {
        Random rnd = new Random();
        Name = "DefaultName";
        Image = "DefaultImage";
        Type = "DefaultType";
        Number = rnd.Next(1,9);
        Sensors = new ObservableCollection<Sensor>();
        Actuators = new ObservableCollection<Actuator>();
    }

    public Room(int inputNumber)
    {
        Name = "DefaultName";
        Image = "DefaultImage";
        Type = "DefaultType";
        Number = inputNumber;
        Sensors = new ObservableCollection<Sensor>();
        Actuators = new ObservableCollection<Actuator>();
    }

    public static Room CreateNewRoom(int inputNumber)
    {
        return new Room(inputNumber);
    }
}

我使用本指南作为实施文档 (https://github.com/Windows-XAML/Template10/wiki/MVVM)。知道为什么 UI 没有更新吗?谢谢。

大多数人(包括我自己)在习惯 'old' Binding 语法时常犯的一个错误是 x:Bind 默认绑定 OneTime 而不是 OneWay绑定。

Mode: Specifies the binding mode, as one of these strings: "OneTime", "OneWay", or "TwoWay". The default is "OneTime". Note that this differs from the default for {Binding}, which is "OneWay" in most cases.

来源:MSDN

要使绑定更新生效,您需要的是:

  • 使用 INotifyPropertyChanged,这由 BindableBase 处理。
  • 设置正确的模式,例如

    Text="{x:Bind ViewModel.Room.Number, Mode=OneWay}