2

現在、WP7 の TimePicker、特に ViewModel へのバインドに問題があります。問題の TimePicker は、アラームの時刻を設定します。ページが最初に読み込まれると、TimePicker は Alarm オブジェクトの値を正しく表示します (この場合、デフォルト値は午前 12:00 です)。ただし、ユーザーが新しい値を選択すると、これはモデルに反映されず、以前の値である午前 12:00 で上書きされます。

MVVM を使用してこのフォームを作成し、データ バインディングを保持しています。私が間違っていることは特にありますか?

(表示) AlarmEditorControl.xaml

<TextBlock Height="30" HorizontalAlignment="Left" Margin="1,6,0,0" Name="lblAlarmTime" Text="Alarm Time:" VerticalAlignment="Top" Grid.Column="2" FontSize="26" />
<!-- Data binding isn't working for updates! -->
<toolkit:TimePicker HorizontalAlignment="Left" Margin="140,34,0,0" Name="tpAlarmTime" VerticalAlignment="Top" Width="161" Grid.Column="1" Grid.ColumnSpan="2" Value="{Binding Path=Time, Mode=TwoWay}" />

(ViewModel) AlarmEditorModel.cs

[DataContractAttribute]
public class AlarmEditorModel
{
    private int _index;

    [DataMemberAttribute]
    public Alarm Alarm { get; set; }

    [DataMemberAttribute]
    public int Index
    {
        get
        {
            return _index;
        }

        set
        {
            _index = value;
        }
    }

    public AlarmEditorModel(int index)
    {
        _index = index;
        Alarm = new Alarm();

        // Get the list of alarms
        AlarmSerializer serializer = new AlarmSerializer();

        // Check the index is in range
        List<Alarm> alarms = serializer.AlarmList;
        if (_index > -1 && index < alarms.Count)
        {
            Alarm = alarms[_index];
        }
    }

    public void Commit()
    {
        // Get the current list of alarms
        AlarmSerializer serializer = new AlarmSerializer();
        List<Alarm> alarms = serializer.AlarmList;

        // Replace our new value
        alarms[_index] = Alarm;
        serializer.AlarmList = alarms;
    }
}

(モデル) Alarm.cs

[DataContract]
public class Alarm : INotifyPropertyChanged
{
    private bool _active;
    private DateTime _time;

    [DataMember]
    public string Name { get; set; }

    [DataMember]
    public DateTime Time
    {
        get
        {
            return _time;
        }
        set
        {
            if (_time != value)
            {
                _time = value;
                RaisePropertyChanged("Time");
            }
        }
    }

    [DataMember]
    public AlarmFrequency Frequency { get; set; }

    [DataMember]
    public AlarmTone Tone { get; set; }

    [DataMember]
    public bool Active { 
        get {
            return _active;
        }
        set {
            _active = value;
        } 
    }

    public string AlarmTimeString { 
        get {
            return Time.ToShortTimeString();
        }
    }



    /**
     * Default Constructor
     */
    public Alarm()
    {
        Debug.WriteLine("Alarm: Using default constructor");
        this.Name = "New Alarm";
        this.Time = DateTime.Today;
        this.Frequency = new AlarmFrequency();
        this.Tone = new AlarmTone();
        this.Active = true;

        Debug.WriteLine("Alarm hours is " + this.Time.Hour);
    }

    /**
     * Parameterised constructor
     */
    public Alarm(string Name, DateTime Time, AlarmFrequency Frequency,
                    AlarmTone Tone, bool Active)
    {
        Debug.WriteLine("Alarm: Using parameterised constructor");
        this.Name = Name;
        this.Time = Time;
        this.Frequency = Frequency;
        this.Tone = Tone;
        this.Active = Active;
       }
}

(呼び出しページ) NewAlarm.xaml.cs

 private List<Channel> feeds;
    private AlarmEditorModel _aem;
    private int _index;

    public NewAlarm()
    {
        InitializeComponent();

        feeds = new List<Channel>();
        feeds.Add(new Channel(null, null, "Feed 1", DateTime.Now));
        feeds.Add(new Channel(null, null, "Feed 2", DateTime.Now));
    }

    /**
     * Setup functions when the page is loaded
     */
    protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
    {
        // Function vars + debug

        Debug.WriteLine("Navigating to");

        // Check if we're recovering from tombstone
        if (!StateUtilities.IsLaunching && this.State.ContainsKey("AlarmState"))
        {
            // Recover the saved model
            _aem = (AlarmEditorModel)this.State["AlarmState"];
        }
        else 
        {
            try
            {
                // Editing an alarm.
                _index = Convert.ToInt32(this.NavigationContext.QueryString["index"]);
                Debug.WriteLine("Editing an alarm");
            }
            catch (KeyNotFoundException knfe)
            {
                Debug.WriteLine(knfe.Message);

                // No index provided, new alarm
                _index = -1;
            }

            // Set the model from the index
            _aem = new AlarmEditorModel(_index);
        }

        AlarmEditor.DataContext = _aem.Alarm;
        Debug.WriteLine(_aem.Alarm.Time.Hour);
    }

    /**
     * Preserve alarm details when tombstoning
     */
    protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
    {
        base.OnNavigatedFrom(e);

        if (this.State.ContainsKey("AlarmState"))
        {
            this.State["AlarmState"] = _aem;
        }
        else
        {
            this.State.Add("AlarmState", _aem);
        }

        StateUtilities.IsLaunching = false;
    }

編集1

Alarm.Time のセッターが 2 回呼び出されているように見えます。次のデバッグ行を Time プロパティに追加します。

[DataMember]
    public DateTime Time
    {
        get
        {
            return _time;
        }
        set
        {
            Debug.WriteLine("Current time is " + _time.ToShortTimeString());
            Debug.WriteLine("New time is " + value.ToShortTimeString());

            if (_time != value)
            {
                Debug.WriteLine("Changing time value");
                _time = value;
                RaisePropertyChanged("Time");
            }
        }
    }

時刻を午前 9 時 10 分に設定すると、ログに次の出力が生成されます。

Current time is 4:00 AM
New time is 9:10 AM 
Changing time value
Current time is 12:00 AM 
New time is 4:00 AM 
Changing time value
4

1 に答える 1

1

問題は解決したと思います。OnNavigatedToViewModelによって上書きされる前にTimePickerの値を取得するために、トゥームストーンから回復するときに追加のチェックインを行う必要がありました。

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
        // Check if we're recovering from tombstone
        if (!StateUtilities.IsLaunching && this.State.ContainsKey("AlarmState"))
        {
            // Recover the saved model
            _aem = (AlarmEditorModel)this.State["AlarmState"];

            // Use the value from the TimePicker
            _aem.Alarm.Time = (DateTime)AlarmEditor.tpAlarmTime.Value;
        }
        else 
        ...

このソリューションでさらにいくつかのテストを行う必要がありますが、これまでのところその仕事をしているようです。

于 2012-05-01T15:33:40.480 に答える