【问题标题】:Template10 UI not refreshing after property changed属性更改后 Template10 UI 不刷新
【发布时间】:2017-04-06 17:49:50
【问题描述】:

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

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 没有更新的任何想法?谢谢。

【问题讨论】:

  • 经过进一步调查,我读到问题可能是绑定需要是 OneWay,因为这不是默认值。以后有时间我再试试。

标签: c# mvvm uwp template10


【解决方案1】:

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

Mode:将绑定模式指定为以下字符串之一:“OneTime”、“OneWay”或“TwoWay”。默认值为“一次性”。请注意,这与 {Binding} 的默认值不同,在大多数情况下为“OneWay”。

来源:MSDN

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

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

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

【讨论】:

  • 感谢您的帮助。现在主要属性的更新工作,尽管如果我在 ObservableCollections 的元素之一中更改某些内容,它不会更新 UI。我的结构是:Room(Properties + Actuator ObservableColletion) => Actuator (Properties + ActuatorStatus ObservableColletion)。虽然我已经在 Actuator 和 ActuatorStatus 模型中实现了 BindableBase,但 UI 没有得到更新。所有的绑定现在都是 OneWay。
  • 由于某种原因,在 ListView 内部,使用 "{x:Bind xxx, Mode=OneWay}" 不会让 UI 得到更新,但是 "{Binding xxx, Mode=OneWay}"完美运行。再次感谢您的帮助。
  • @Carlos 你能重现 x:bind 的行为吗?如果您可以可靠地给我发送重现项目的链接,我会告诉团队。如果可以,请在 Microsoft.com 上给我发电子邮件 @Jerry.Nixon。
猜你喜欢
  • 2010-11-10
  • 2020-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多