Silverlight用户控件中的自定义绑定

3
我在一个MVVM Silverlight应用程序中遇到了将自定义用户控件绑定到ViewModel的问题。这个基本控件是一个带有三个文本框的日期输入表单。我正在使用MVVM在三个属性中获取文本框数据,然后将其验证为日期。
将下面的控件绑定到MVVM对我来说没问题: 用户控件的XAML: DateControl.xaml
<UserControl x:Class="DatePicker.DateControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid x:Name="LayoutRoot" Background="White"
          HorizontalAlignment="Center">
        <StackPanel Orientation="Horizontal">
            <StackPanel Orientation="Horizontal">
                <TextBox MaxLength="2" TabIndex="0" Style="{StaticResource BirthDDTextBoxStyle}"
                                Text="{Binding BirthDay,Mode=TwoWay,ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}"/>
                <TextBlock  Style="{StaticResource TextBlockStyle_DateSeperator}"/>
                <TextBox MaxLength="2" TabIndex="1" Style="{StaticResource BirthDDTextBoxStyle}" Text="{Binding BirthMonth, Mode=TwoWay,ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}"/>
                <TextBlock   Style="{StaticResource TextBlockStyle_DateSeperator}"/>
                <TextBox MaxLength="4" TabIndex="2" Style="{StaticResource BirthYYTextBoxStyle}" Text="{Binding BirthYear, Mode=TwoWay, ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}"/>
                <Button Content="Show" Width="100" Height="30" Click="Button_Click"/>
            </StackPanel>
        </StackPanel>
    </Grid>
</UserControl>

DateControlViewModel:

namespace DatePicker
{
    public class DatePickerViewModel : EntityViewModel
    {
        public DatePickerViewModel()
        {

        }

        private DateTime birthDate;
        public DateTime BirthDate
        {
            get
            {

                return birthDate;
            }
            set
            {
                birthDate = value;
            }
        }
        private string birthDay;
        public string BirthDay
        {
            get { return birthDay; }
            set
            {
                birthDay = value;
                PropertyChangedHandler("BirthDay");
                ValidateBirthDay("BirthDay", value);
            }
        }

        private string birthMonth;
        public string BirthMonth
        {
            get { return birthMonth; }
            set
            {
                birthMonth = value;
                PropertyChangedHandler("BirthMonth");
                ValidateBirthMonth("BirthMonth", value);
            }
        }

        private string birthYear;
        public string BirthYear
        {
            get { return birthYear; }
            set
            {
                birthYear = value;
                PropertyChangedHandler("BirthYear");
                ValidateBirthYear("BirthYear", value);
            }
        }

        private void ValidateDOB()
        {
            ClearErrorFromProperty("BirthDay");
            ClearErrorFromProperty("BirthMonth");
            ClearErrorFromProperty("BirthYear");
            if (string.IsNullOrEmpty(BirthDay))
                ValidateBirthDay("BirthDay", BirthDay);
            if (string.IsNullOrEmpty(BirthMonth))
                ValidateBirthMonth("BirthMonth", BirthMonth);
            if (string.IsNullOrEmpty(BirthYear))
                ValidateBirthYear("BirthYear", BirthYear);
            if (!string.IsNullOrEmpty(BirthDay) && !string.IsNullOrEmpty(BirthMonth) && !string.IsNullOrEmpty(BirthYear))
                SetDateOfBirth();
        }

        private void ValidateBirthDay(string propertyName, string value)
        {
            ClearErrorFromProperty(propertyName);
            if (String.IsNullOrEmpty(value))
                AddErrorForProperty(propertyName, "Resources.PatientImport.EmptyDayMessage");
            else
                if (Common.IsNumber(value))
                {
                    int day = Convert.ToInt32(value);
                    if (day > 31 || day < 1)
                        AddErrorForProperty(propertyName, "Resources.PatientImport.InvalidDayMessage");
                }
                else
                    AddErrorForProperty(propertyName, "Resources.PatientImport.InvalidDayMessage");
        }

        private void ValidateBirthMonth(string propertyName, string value)
        {
            ClearErrorFromProperty(propertyName);
            if (String.IsNullOrEmpty(value))
                AddErrorForProperty(propertyName, "Resources.PatientImport.EmptyMonthMessage");
            else
                if (Common.IsNumber(value))
                {
                    int month = Convert.ToInt32(value);
                    if (month > 12 || month < 1)
                        AddErrorForProperty(propertyName, "Resources.PatientImport.InvalidMonthMessage");
                }
                else
                    AddErrorForProperty(propertyName, "Resources.PatientImport.InvalidMonthMessage");
        }

        private void ValidateBirthYear(string propertyName, string value)
        {
            ClearErrorFromProperty(propertyName);
            if (String.IsNullOrEmpty(value))
                AddErrorForProperty(propertyName, "Resources.PatientImport.EmptyYearMessage");
            else
                if (Common.IsNumber(value))
                {
                    int year = Convert.ToInt32(value);
                    if (year.ToString().Length > 4 || year.ToString().Length < 4)
                        AddErrorForProperty(propertyName, "Resources.PatientImport.InvalidYearMessage");
                }
                else
                    AddErrorForProperty(propertyName, "Resources.PatientImport.InvalidYearMessage");
        }

        private void SetDateOfBirth()
        {
            string dateString = BirthDay + "-" + BirthMonth + "-" + BirthYear;
            DateTime date;
            if (!DateTime.TryParse(dateString.ToString(), out date))
            {
                ClearErrorFromProperty("BirthDay");
                ClearErrorFromProperty("BirthMonth");
                ClearErrorFromProperty("BirthYear");
                AddErrorForProperty("BirthDay", "Resources.PatientImport.InvalidDayMessage");
                AddErrorForProperty("BirthMonth", "Resources.PatientImport.InvalidMonthMessage");
                AddErrorForProperty("BirthYear", "Resources.PatientImport.InvalidYearMessage");
            }
            else
                BirthDate = date;
        }
    }
}

我想在我的MainPage.xaml中使用这个控件:

<UserControl x:Class="DatePicker.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:DatePicker"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <local:DateControl />
    </Grid>
</UserControl>

我希望在DateControl中定义一个属性,用于将我的用户控件与MainPage.xaml的ViewModel进行绑定。

类似这样:

<Grid x:Name="LayoutRoot" Background="White">
    <local:DateControl Date="{Binding BirthDate, Mode=TwoWay, ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}"/>
</Grid>

BirthDate是字符串类型的属性。

我该如何更改我的用户控件,以便在MainPage.XAML中使用单独的MVVM绑定其属性?


你应该阅读编辑帮助,因为格式很混乱... - H.B.
请查看这个答案。https://dev59.com/CXVD5IYBdhLWcg3wI3-L - Aardvark
你为什么要在你的UserControl中添加Date属性?视图可以完全不需要代码存在,一切都可以通过视图模型完成。 - vortexwolf
1个回答

1
首先,您需要将DateControlDataContext设置为DateControlViewModel。在您的DateControl xaml中,您可以使用此想法,或者在代码中的某个位置进行设置(例如DateControl的构造函数),或者将DataContext数据绑定到要使用的视图模型。
 <UserControl.Resources>
        <viewModels:ViewDisplayTemplatesViewModel x:Key="viewModel" />
    </UserControl.Resources>

    <UserControl.DataContext>
        <Binding Source="{StaticResource viewModel}"/>
    </UserControl.DataContext>

其次,您需要在您的DateControl中定义一个依赖属性,正如Aardvark在评论中提到的那样。我使用propdp代码段(我认为它随着Silverlight安装而来,如果没有,您可以在这个MSDN文章中看到它)。依赖属性使xaml绑定成为可能。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接