【问题标题】:Can't get the CalendarDatePicker in UWP behaviour right in MVVM无法在 MVVM 中正确获取 UWP 行为中的 CalendarDatePicker
【发布时间】:2016-06-28 21:53:30
【问题描述】:

UWP 应用非常简单。具有属性的 ViewModel 由包含 CalendarDatePicker 的页面绑定。

查看模型:

public class MainPageViewModel : INotifyPropertyChanged
{
    private DateTimeOffset date;

    public MainPageViewModel()
    {

    }

    public event PropertyChangedEventHandler PropertyChanged;

    public DateTimeOffset Date
    {
        get { return date; }
        set
        {
            date = value; 
            OnPropertyChanged();
        }
    }

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

页面:

<Page
x:Class="App2.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App2"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.DataContext>
    <local:MainPageViewModel />
</Page.DataContext>

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <CalendarDatePicker />
</Grid>
</Page>

我运行这个应用程序,CalendarDatePicker 的行为符合预期。启动时未选择日期,显示“选择日期”字眼,展开时默认为今天的日期。

当我将 CalendarDatePicker Date 属性绑定到我的虚拟机的日期并运行应用程序时,日期默认为 1916 年 4 月 16 日。

我尝试将Date 设为可空,将绑定模式更改为TwoWay 以及许多其他方法均无济于事。

有没有人遇到过同样的问题?如何在 MVVM 中使用此控件?

【问题讨论】:

    标签: c# mvvm win-universal-app


    【解决方案1】:

    当我将 CalendarDatePicker 日期属性绑定到我的虚拟机的日期并运行应用程序时,日期默认为 1916 年 4 月 16 日。

    我不知道究竟是什么导致了问题,但它返回了一个Date,它比MinDate 更小。

    当您在代码中设置日期时,该值受 MinDate 和 MaxDate 属性的约束。如果 Date 小于 MinDate,则该值设置为 MinDate。如果 Date 大于 MaxDate,则将该值设置为 MaxDate。

    您可以参考 CalendarDatePicker class 来查看此内容,您认为 MinDate 是“1916 年 4 月 16 日”,而我现在是“3/15/1916 4:27:52 PM +08:00”。

    但是我发现你的班级有问题@​​987654329@。

    查看CalendarDatePicker.Date property会发现Date不是DateTimeOffset的类型,它的类型是Nullable&lt;DateTimeOffset&gt;

    这就是我的工作方式。 主页 XAML 代码:

    <Page
        x:Class="CalendarDatePickerInMVVM.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:CalendarDatePickerInMVVM"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <CalendarDatePicker x:Name="picker" HorizontalAlignment="Center"  Date="{x:Bind MainPageViewModel.Date}" />
            <TextBox x:Name="txt" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" />
        </Grid>
    </Page>
    

    MainPage.cs 后面的代码:

    public sealed partial class MainPage : Page
    {
        private ViewModel.MainPageViewModel MainPageViewModel;
        public MainPage()
        {
            this.InitializeComponent();
            txt.Text = picker.MinDate + "......" + picker.MaxDate;
            MainPageViewModel = new ViewModel.MainPageViewModel();
        }
    }
    

    还有班级MainPageViewModel : INotifyPropertyChanged

    public class MainPageViewModel : INotifyPropertyChanged
    {
        private System.Nullable<DateTimeOffset> date;
    
        public MainPageViewModel()
        {
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        public System.Nullable<DateTimeOffset> Date
        {
            get { return date; }
            set
            {
                date = value;
                OnPropertyChanged();
            }
        }
    
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    

    如果你想给你的CalendarDatePicker一个默认值,你可以这样编码:

    private System.Nullable<DateTimeOffset> date = new DateTime(2016, 3, 15);
    

    【讨论】:

    • 就像我在原帖中所说的那样,我尝试让 Date 可以为空,如下所示:public DateTimeOffset? Date。然后我绑定到它:&lt;CalendarDatePicker Date="{Binding Date, Mode=TwoWay}" /&gt;。绑定很好,因为当我在 getter 上放置断点时,它会被命中。但是,当绑定存在于 xaml 中时,当Date 为空时,我不会得到 select a date 措辞,而且我如何初始化 Date 值并不重要,控件始终显示1916 年 4 月 16 日。
    • @JoaoMilasch,好的,也许你的问题不在于绑定,但它必须返回一个比 MinDate 更小的日期。从您发布的代码中,除了Date 类型应该是Nullable&lt;DateTimeOffset&gt; 之外,我不知道您的问题到底是什么,但请尝试我的答案中的代码,它仍然可以正常工作。我刚刚编辑了我的答案。
    • 谢谢!是的,你是对的,发布的代码并没有说明我的尝试之一。我确实尝试了你的代码,它确实有效。挖掘差异后,我惊讶地发现 {x:Bind} 直到现在我才知道存在,而不是旧 WPF 时代的 {Binding} 标记。当我切换你的代码声明MainPageViewModelMainPageDataContext 并使用{Binding Date} 时,你的代码(那时几乎与我的代码完全一样)不再起作用。虽然我会查找两者之间的差异以试图理解你知道为什么一个有效而另一个无效吗?
    • @JoaoMilasch,是的,你是对的,我刚刚再次尝试使用 Binding 和 DataContext,我也遇到了错误,我目前不知道为什么会发生这种情况。 x:Bind 是 Windows 10 的新功能,但 {x:Bind} 执行专用代码,它在编译时生成,而 {Binding} 使用通用运行时对象检查。我认为在编译时初始化CalendarDatePicker 可能会有所不同。 {x:Bind} markup extension的文档。
    • @JoaoMilasch,从您的代码中,我认为您希望在CalendarDatePicker 中更改Date 时收到通知,为此,您还可以绑定事件DateChanged,如果您想知道如何绑定事件,请参考Event binding and ICommand
    【解决方案2】:

    我还没有使用过 CalendarDatePicker 和 MVVM,但根据你所说的判断,我认为 VM 中 Date 属性的值默认为某个值。然后,当绑定发生时,控件将该默认值解释为 1916 年 4 月 16 日。

    尝试使 VM 中的 Date 可以为空(以匹配控件中属性的类型)并用所需的值预填充它以查看其行为方式。

    如果你不能让它以任何方式与绑定一起工作,你可以尝试在后面的代码中为控件实现一个事件处理程序(也许this 处理程序会这样做)并在那里更新你的虚拟机

    【讨论】:

    • 感谢您的建议,正如帖子中所说,我确实尝试将 Date 设为可空,并尝试了不同的初始值组合。
    猜你喜欢
    • 1970-01-01
    • 2017-06-17
    • 1970-01-01
    • 2017-04-02
    • 1970-01-01
    • 2016-07-10
    • 1970-01-01
    • 1970-01-01
    • 2017-02-20
    相关资源
    最近更新 更多