2010-08-09 56 views
2

我正在增強一個開源控件,以添加一些我需要的功能,並且我正陷入以下問題的絕望之中:Silverlight依賴屬性snafu,我做錯了什麼?

控件是一個支持HTML但不通過屬性的富文本框;你必須做這樣的事情:

var sHtml = "..." 
ctrl.LoadHtml(sHtml) 

var sHtml = ctrl.SaveHtml() 

到目前爲止好。但我想通過設置數據綁定的HTML,所以我做了稱爲HTML依賴屬性:

public static readonly DependencyProperty HtmlProperty = 
     DependencyProperty.Register(
      "Html", 
      typeof(string), 
      typeof(RichTextEditor), 
      new PropertyMetadata(string.Empty, new PropertyChangedCallback(HtmlChangedCallback)) 
      ); 

    public string Html 
    { 
     get {return (string)GetValue(HtmlProperty);} 

     set {SetValue(HtmlProperty, value);} 
    } 

    private static void HtmlChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     //get the control 
     var rte = (RichTextEditor)d; 

     //got here, so load the html 
     rte.TextBox.LoadHtml((string)e.NewValue); 
    } 

這一切工作正常。我遇到的問題是,當控制內容發生變化時,我無法知道如何通知財產系統。該控制裝置具有一個ContentChanged事件,所以我想這:

private void rtb_ContentChanged(object sender, RichTextBoxEventArgs e) 
    { 
     //tell the html prop that it changed 
     SetValue(HtmlProperty, rtb.SaveHtml()); 
    } 

但這然後觸發HtmlChangedCallback和再侵入引起的問題。所以我嘗試使用重新入口的標誌,但是這樣做很麻煩,因爲事件的順序比我預期的要複雜得多,而且在這一點上,我想我必須錯過一些東西,所以我在這裏問。請幫忙!提前致謝。

順便說一句,該控件不支持INotifyPropertyChanged,並且實現它超出了範圍,因爲控件很大,我不想做那麼多工作。

+0

「再入口」的原因是什麼問題? – Jacob 2010-08-09 22:49:14

+0

嗯,最初的問題是,在HtmlChangedCallback中,我將HTML加載到控件中,該控件觸發Content_Changed事件,並調用Content_Changed中的SetValue導致HtmlChangedCallback觸發,並且在Silverlight轉義出無限循環之前我看到了很多輪。我試着自己設置一個再入口標誌,但是我發現事件的順序是不可預測的,有時他們的事件會不順序,而不是試圖弄清楚,我可以告訴我做錯了事,如果我不得不砍掉那麼多。 – 2010-08-09 23:05:25

回答

0

這是一個經典的小問題,通常用一個簡單的布爾標誌來解決。

private bool suppressHtmlChanged = false; 

private static void HtmlChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 

    var rte = (RichTextEditor)d; 

    if (!rte.suppressHtmlChanged) 
     rte.TextBox.LoadHtml((string)e.NewValue); 
} 


private void rtb_ContentChanged(object sender, RichTextBoxEventArgs e) 
{ 
    suppressHtmlChanged = true; 
    SetValue(HtmlProperty, rtb.SaveHtml()); 
    suppressHtmlChanged = false; 
} 

這些天,這樣的解決方案顯得那麼老氣是不是,我們經常可以說服自己,因爲他們不是「優雅」這樣的「低科技」的解決方案不可能是正確的。

+0

是的,這確實有竅門,但由於這種控制方式引發事件的方式在具體情況中變得更加複雜。謝謝。 – 2010-08-10 16:00:27

0

爲什麼你需要通知財產製度?您是否嘗試更新數據綁定的來源?該控件不必實現INotifyPropertyChanges;這個接口必須在爲數據綁定提供數據的類上實現。

如果您現在忽略Save/LoadHtml並將HTML存儲爲字符串會怎麼樣?它沒有問題嗎?

這是這對我來說工作正常

class MyControl 
{ 
    public int Value 
    { 
     get 
     { 
      return (int)GetValue(ValueProperty); 
     } 

     set 
     { 
      SetValue(ValueProperty, value); 
      Count.Text = value.ToString(); 
     } 
    } 

    public static readonly DependencyProperty ValueProperty = 
     DependencyProperty.Register("Value", 
      typeof(int), 
      typeof(Vote), 
      new PropertyMetadata(0, OnValueChanged)); 

    private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     ((MyControl)d).Value = (int)e.NewValue; 
    } 

計數是一個文本塊控制的例子。

+0

是的,我有一個ViewModel,當視圖中的Html(即富文本框)發生更改時,它應該被更新。不,它只是存儲字符串不起作用,因爲屬性系統無法知道View已經改變了字符串。我的問題是:什麼時候發生這種事情的正確方式? – 2010-08-09 23:01:05

+0

您是否在{Binding}語句中指定了雙向模式?爲了工作,你需要三件事 - 模型應該實現INotifyPropertyChanges並調用屬性更改事件 - 視圖應該使用依賴屬性(使用Get/SetValue存儲) - XAML應該指定雙向模式 – AlexEzh 2010-08-09 23:11:18

+0

我不認爲這三個步驟已經足夠了,因爲我已經完成了所有這些步驟。在進一步思考之後,我認爲缺少的部分是相當普遍的:當你指定一個綁定來更新來自View的源碼(比如TwoWay),並且View沒有實現INPC時,它將如何工作?也就是說,View必須通知某個屬性發生了變化,我認爲應該可以通過DependencyProperty來實現,但我不太確定,因爲我找不到它。因此,如果我希望View支持更新Source,View可能需要實現INPC。 – 2010-08-09 23:31:22