2011-05-06 21 views
2

我正在構建一個使用WPF和MVVM的應用程序。我碰到過一個包含一個usercontrol(代表一個Timer)的視圖。這個用戶控件在其代碼後面有一個屬性,它在獲取和設置數據之前執行一些計算。綁定到用戶控件的屬性,包含邏輯,在視圖模型中的屬性

TimerControl.xaml.cs:

public DateTime? DateTimeValue 
    { 
     get 
     { 
      string hours = this.txtHours.Text; 
      string minutes = this.txtMinutes.Text; 
      string amPm = this.txtAmPm.Text; 
      if (!string.IsNullOrWhiteSpace(hours) && !string.IsNullOrWhiteSpace(minutes) && !string.IsNullOrWhiteSpace(amPm)) 
      { 
       string value = string.Format("{0}:{1} {2}", this.txtHours.Text, this.txtMinutes.Text, this.txtAmPm.Text); 
       DateTime time = DateTime.Parse(value);      
       return time; 
      } 
      else 
      { 
       return null; 
      } 
     } 
     set 
     {     
      DateTime? time = value; 
      if (time.HasValue) 
      { 
       string timeString = time.Value.ToShortTimeString(); 
       //9:54 AM 
       string[] values = timeString.Split(':', ' '); 
       if (values.Length == 3) 
       { 
        this.txtHours.Text = values[0]; 
        this.txtMinutes.Text = values[1]; 
        this.txtAmPm.Text = values[2]; 
       } 
      }     
     } 
    } 

現在,我想這個屬性與存在於視圖中的視圖模型的屬性。以下是在虛擬機屬性:

public DateTime? StartTime 
{ 
     get 
     {     
      return _StartTime; 
     } 

     set 
     { 
      _StartTime = value; 
      RaisePropertyChanged("StartTime"); 
     } 
} 

這是怎麼了表演鑑於XAML綁定。

MyView.xaml:

<my:TimeControl Background="White" Grid.Column="1" Grid.Row="2" Margin="3" x:Name="StartTimeControl" DateTimeValue="{Binding StartTime}" Width="150" Height="26" HorizontalAlignment="Left"> 

但它給我一個錯誤: A '綁定' 無法在類型 'TimeControl' 的 'DateTimeValue' 屬性設置。 '綁定'只能在DependencyObject的DependencyProperty上設置。

我一直在掙扎了幾個小時試圖找出一種方法,使這種結合工作。我甚至試圖在TimeControl的代碼中爲DateTimeValue屬性創建一個依賴屬性,該屬性解決了上述異常,但綁定仍然無效。每當我在後面的VM代碼中訪問StartTime屬性時,它都顯示爲空。雖然它應該通過獲取DateTimeValue屬性來顯示有效值。

請給我建議的方式來完成這項工作。謝謝。

回答

2

你的實現在這個問題上顯示DateTimeValue財產肯定是錯誤的,並導致異常,因爲DateTimeValue應該是依賴項屬性。

但你提到你曾嘗試使用依賴屬性,但沒有成功。我想原因是DataContexts和你的XAML相沖突:

<UserControl x:Class="Test.SomeView" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:self="clr-namespace:Test" 
      Name="Root"> 
    <WrapPanel> 
     <self:TimerControl Time="{Binding StartTime}"/> 
    </WrapPanel> 
</UserControl> 

此代碼不起作用。爲什麼? TimerControl的DataContext是繼承的(或者你可能會替換它),同時,當你處理StartTime時,你將ViewModel作爲DataContext記住。所以,你應該明確地指向正確的DataContext:

<self:Timer Time="{Binding DataContext.StartTime, ElementName=Root}"/> 

=== UPDATE ===

我的定時器控制的整個代碼(你可以看到我的定時器有文本框,當你輸入一些文本,文本提出了相應的事件,這是我們處理和設置時間屬性):

public partial class Timer : UserControl 
{ 
    public Timer() 
    { 
     InitializeComponent(); 
    } 

    public DateTime? Time 
    { 
     get 
     { 
      return (DateTime?)this.GetValue(Timer.TimeProperty); 
     } 
     set 
     { 
      this.SetValue(Timer.TimeProperty, value); 
     } 
    } 

    public static readonly DependencyProperty TimeProperty = 
     DependencyProperty.Register("Time", 
      typeof(DateTime?), 
      typeof(Timer), 
      new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, (d, e) => { })); 

    private void TextBox_TextChanged(object sender, TextChangedEventArgs e) 
    { 
     if (DateTime.Now.Ticks % 2 == 0) 
     { 
      this.Time = DateTime.Now; 
     } 
     else 
     { 
      this.Time = null; 
     } 
    } 

} 

和XAML:

<UserControl x:Class="Test.Timer"> 
    <Grid> 
     <TextBox TextChanged="TextBox_TextChanged"/> 
    </Grid> 
</UserControl> 
在XAML

使用時間控制:

<UserControl x:Class="Test.StartupView" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:self="clr-namespace:Test" 
      Name="Root"> 
    <WrapPanel> 
     <self:Timer Time="{Binding DataContext.StartTime, ElementName=Root}"/> 
    </WrapPanel> 
</UserControl> 

StartupView的背後代碼:

public StartupView() 
    { 
     InitializeComponent(); 
     this.DataContext = new ViewModel(); 
    } 

屬性,視圖模型保持不變。每當我在Timer中更改文本時,StartTime屬性的調試設置器都會觸發。

+0

謝謝亞歷克斯!綁定仍然不起作用。這就是我定義依賴屬性DateTimeValue:公共只讀靜態的DependencyProperty DateTimeValueProperty = DependencyProperty.Register( 「DateTimeValue」 的typeof(DateTime的)的typeof(TimeControl),新FrameworkPropertyMetadata(){ PropertyChangedCallback = OnDemoChanged, BindsTwoWayByDefault =真 });此外,爲了工作,我需要將GetValue和SetValue保存在DateTimeValue的get和set中。但在我的場景中,我有一些邏輯。 – 2011-05-06 13:21:31

+0

我已經更新了我的答案。你應該把你的邏輯放在其他地方,而不是DP。例如DP有CoerceValueCallback,試試吧。 – 2011-05-06 13:33:20

+0

謝謝亞歷克斯!你的解決方案確實有幫我已經從DP的getter和setter中移除了邏輯,並將其保存在一個函數中,該函數每次在計時器控件的任何文本框中更改數據時都會調用該函數。另外我在xaml中進行綁定的方式是錯誤的。但按照您指定的方式完成後,事情就開始奏效了。再次感謝 ! – 2011-05-06 16:16:30

2

你想幹什麼?

您不能綁定到一個標準的屬性。如果你想綁定你應該使用依賴屬性。

public DateTime? DateTimeValue 
{ 
    get { return (DateTime?)GetValue(DateTimeValueProperty); } 
    set { SetValue(DateTimeValueProperty, value); } 
} 

// Using a DependencyProperty as the backing store for DateTimeValue. This enables animation, styling, binding, etc... 
public static readonly DependencyProperty DateTimeValueProperty = 
    DependencyProperty.Register("DateTimeValue", typeof(DateTime?), typeof(TimeControl), new UIPropertyMetadata(null)); 

的用戶控件內部:

<TextBox Text="{Binding DateTimeValue,RelativeSource={RelativeSource AncestorLevel=1, Mode=FindAncestor,AncestorType=UserControl}, Converter=...}" /> 

直接綁定到DateTimeValue是不可能的,因爲沒有可爲string>日期時間轉換器,所以你必須寫的IValueConverter並指定此您捆綁。

從課程之外,你應該能值直接綁定。

+0

謝謝! VM中的StartTime屬性和用戶控件中的DateTimeValue屬性都是DateTime類型? 。我還需要轉換器嗎?此外,我不綁定TimeControl中存在的任何單獨控件,而是將其後面代碼中定義的屬性綁定到VM中的一個屬性,即StartTime – 2011-05-06 13:12:24

+0

當然,如果您使用f.e.則只需要轉換器。想要將DateTimeValue綁定到TextBox或類似的。 VM屬性也是「DateTime?」,是的。 – SACO 2011-05-06 13:17:25

相關問題