具有代码隐藏的WPF MVVM + UserControl

时间:2009-04-15 17:44:39

标签: .net wpf mvvm user-controls

由于某种原因,我遇到问题通过我的ViewModel在MVVM WPF应用程序中绑定自定义用户控件。基本控件是带有三个文本框的日期输入表单。我使用codebehind为usercontrol捕获textchange事件,因此进行了一些操作。由于某种原因,添加绑定到属性永远不会触发。

用户控件的XAML:

<UserControl x:Class="MYLibray.DateBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="800">
<StackPanel>

    <Border CornerRadius="10" Height="200" BorderBrush="Gray" Background="Gray">
    <StackPanel Orientation="Horizontal" OpacityMask="{x:Null}" HorizontalAlignment="Center">
    <TextBox Name="txtMonth" Height="100" Width="90" BorderThickness="0,0,0,5" Background="{x:Null}" Text="" FontSize="72" TextChanged="TextChanged">
        <TextBox.BorderBrush>
            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                <GradientStop Color="#FF000000" Offset="0"/>
                <GradientStop Color="#FF000000" Offset="1"/>
            </LinearGradientBrush>
        </TextBox.BorderBrush>
    </TextBox>
            <TextBlock Text="/" FontSize="72" Height="100" Width="50" />
            <TextBox x:Name="txtDay" Height="100" Width="90" Background="{x:Null}" BorderThickness="0,0,0,5" VerticalAlignment="Stretch" FontSize="72" TextChanged="TextChanged">
                <TextBox.BorderBrush>
                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                        <GradientStop Color="#FF000000" Offset="0"/>
                        <GradientStop Color="#FF000000" Offset="1"/>
                    </LinearGradientBrush>
                </TextBox.BorderBrush>
            </TextBox>
            <TextBlock Text="/19" FontSize="72" Height="100" Width="Auto" />
            <TextBox x:Name="txtYear" Height="100" Width="90" Background="{x:Null}" BorderThickness="0,0,0,5"  FontSize="72" TextChanged="TextChanged">
                <TextBox.BorderBrush>
                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                        <GradientStop Color="#FF000000" Offset="0"/>
                        <GradientStop Color="#FF000000" Offset="1"/>
                    </LinearGradientBrush>
                </TextBox.BorderBrush>
            </TextBox>
    </StackPanel>
    </Border>

</StackPanel>

代码隐藏:

public partial class DateBox : UserControl

{

  private string _date = "";
  public static DependencyProperty TextProperty = DependencyProperty.RegisterAttached("DateText", typeof(string), typeof(DateBox), new PropertyMetadata(TextPropertyChanged));
  public static DependencyProperty EnabledProperty = DependencyProperty.RegisterAttached("Enabled", typeof(bool), typeof(DateBox), null);

  public DateBox()
  {                                 
     InitializeComponent();
     this.DataContext = this;
     txtMonth.Focus();
  }

  public bool Enabled
  {
     get
     {
        return (bool)GetValue(DateBox.EnabledProperty);
     }
     set
     {
        SetValue(DateBox.EnabledProperty, value);

        txtDay.IsEnabled = value;
        txtMonth.IsEnabled = value;
        txtYear.IsEnabled = value;
     }
  }

  public string DateText
  {
     get
     {
        return (string)this.GetValue(TextProperty);
     }
     set
     {
        this.SetValue(TextProperty, value);
     }
  }

  static void TextPropertyChanged(DependencyObject property,DependencyPropertyChangedEventArgs args)
  {
     ((DateBox)property).OnTextPropertyChanged((object)args.NewValue);
  }

  private void OnTextPropertyChanged(object newValue)
  {
     _date = newValue.ToString();
     this.UpdateLayout();
     DateTime d;
     if (DateTime.TryParse(_date, out d))
     {
        txtDay.Text = d.Day.ToString();
        txtMonth.Text = d.Month.ToString();
        txtYear.Text = (d.Year - 1900).ToString();
     }
     else
     {
        txtDay.Text = "";
        txtMonth.Text = "";
        txtYear.Text = "";
     }

     DateText = d.ToShortDateString();
  }

  bool AreAllValidNumericChars(string str)
  {
     bool ret = true;
     if (str == System.Globalization.NumberFormatInfo.CurrentInfo.PositiveSign)
     {
        return ret;
     }
     int l = str.Length;
     for (int i = 0; i < l; i++)
     {
        char ch = str[i];
        ret &= Char.IsDigit(ch);
     }

     return ret;
  }

  private void TextChanged(object sender, TextChangedEventArgs e)
  {

     TextBox txt = (TextBox)sender;

     switch (txt.Name)
     {
        case "txtMonth":
           if (txt.Text.Length == 1)
           {
              if (Convert.ToInt32(txt.Text) > 1)
              {
                 string value = txt.Text;
                 txt.Text = "0" + value;
                 txtDay.Focus();
              }
           }
           if (txt.Text.Length == 2)
           {
              txtDay.Focus();
           }
           break;
        case "txtDay":
           if (txt.Text.Length == 1)
           {
              if (Convert.ToInt32(txt.Text) > 3)
              {
                 string value = txt.Text;
                 txt.Text = "0" + value;
                 txtYear.Focus();
              }
           }
           if (txt.Text.Length == 2)
           {
              txtYear.Focus();
           }
           break;

        case "txtYear":
           if (txt.Text.Length == 2)
           {
              DateTime d;
              string datestring = txtMonth.Text + "/" + txtDay.Text + "/19" + txtYear.Text;
              if (DateTime.TryParse(datestring,out d))
              {
                 DateText = d.ToShortDateString();
              }
           }
           break;
        default:
           break;
     }
  }

}

当我在DataTemplate中创建usercontrol时,如下所示:

<uc:DateBox DateText="{Binding BirthDate}" />

我的ViewModel中的BirthDate的get和set永远不会被设置。 VM上的BirthDate是一个字符串。

1 个答案:

答案 0 :(得分:6)

检查对照和父母的DataContext

帮助调试绑定,请查看Bea Stollnitz's blog

基本上,将此xmlns添加到您的控件

xmlns:diagnostics="clr-namespace:System.Diagnostics;assembly=WindowsBase"

然后将其添加到您的Binding

{Binding ....    , diagnostics:PresentationTraceSources.TraceLevel=High }