2014-05-23 135 views
4

我創建了一個自定義的從AvalonEdit繼承的TextEditor控件。我這樣做是爲了方便使用此編輯器控件來使用MVVM和Caliburn Micro。 [剪切下來用於顯示目的] MvvTextEditor類是使用MVVM在WPF中綁定失敗

public class MvvmTextEditor : TextEditor, INotifyPropertyChanged 
{ 
    public MvvmTextEditor() 
    { 
     TextArea.SelectionChanged += TextArea_SelectionChanged; 
    } 

    void TextArea_SelectionChanged(object sender, EventArgs e) 
    { 
     this.SelectionStart = SelectionStart; 
     this.SelectionLength = SelectionLength; 
    } 

    public static readonly DependencyProperty SelectionLengthProperty = 
     DependencyProperty.Register("SelectionLength", typeof(int), typeof(MvvmTextEditor), 
     new PropertyMetadata((obj, args) => 
      { 
       MvvmTextEditor target = (MvvmTextEditor)obj; 
       target.SelectionLength = (int)args.NewValue; 
      })); 

    public new int SelectionLength 
    { 
     get { return base.SelectionLength; } 
     set { SetValue(SelectionLengthProperty, value); } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    public void RaisePropertyChanged([CallerMemberName] string caller = null) 
    { 
     var handler = PropertyChanged; 
     if (handler != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(caller)); 
    } 
} 

現在,在持有該控制的觀點,我有以下XAML:

<Controls:MvvmTextEditor 
     Caliburn:Message.Attach="[Event TextChanged] = [Action DocumentChanged()]" 
     TextLocation="{Binding TextLocation, Mode=TwoWay}" 
     SyntaxHighlighting="{Binding HighlightingDefinition}" 
     SelectionLength="{Binding SelectionLength, 
            Mode=TwoWay, 
            NotifyOnSourceUpdated=True, 
            NotifyOnTargetUpdated=True}" 
     Document="{Binding Document, Mode=TwoWay}"/> 

我的問題是SelectionLength(和SelectionStart但讓由於問題是相同的,我們只考慮現在的長度)。如果我用鼠標選擇了一些東西,從視圖到我的視圖模型的綁定效果很好。現在,我已經編寫了一個查找和替換實用程序,並且我想從後面的代碼中設置SelectionLength(其中getset可用於TextEditor控件)。在我的視圖模型,我簡單地設置SelectionLength = 50,我在視圖模型實現這個像

private int selectionLength; 
public int SelectionLength 
{ 
    get { return selectionLength; } 
    set 
    { 
     if (selectionLength == value) 
      return; 
     selectionLength = value; 
     Console.WriteLine(String.Format("Selection Length = {0}", selectionLength)); 
     NotifyOfPropertyChange(() => SelectionLength); 
    } 
} 

當我設置SelectionLength = 50,則DependencyProperty SelectionLengthProperty不會在MvvmTextEditor類得到更新,它就像TwoWay綁定到我的控制失敗了,但使用Snoop沒有這個跡象。我認爲這只是通過綁定工作,但似乎並非如此。

有一些簡單的我失蹤,或將我不得不設立,並在MvvmTextEditor類偵聽改變我的視圖模型的事件處理程序,並更新了DP本身[呈現它自身的問題]

謝謝你的時間。

回答

0

這是我這究竟是怎麼...

public static readonly DependencyProperty SelectionLengthProperty = 
    DependencyProperty.Register("SelectionLength", typeof(int), typeof(MvvmTextEditor), 
    new PropertyMetadata((obj, args) => 
     { 
      MvvmTextEditor target = (MvvmTextEditor)obj; 
      if (target.SelectionLength != (int)args.NewValue) 
      { 
       target.SelectionLength = (int)args.NewValue; 
       target.Select(target.SelectionStart, (int)args.NewValue); 
      } 
     })); 

public new int SelectionLength 
{ 
    get { return base.SelectionLength; } 
    //get { return (int)GetValue(SelectionLengthProperty); } 
    set { SetValue(SelectionLengthProperty, value); } 
} 

對不起,浪費的任何時間。我希望這可以幫助別人...

1

這是因爲來自DependencyPropertyGetterSetter只是一個.NET Wrapper。該框架將使用GetValueSetValue本身。

你可以嘗試的是從你的DependencyProperty訪問PropertyChangedCallback並設置正確的值。

public int SelectionLength 
     { 
      get { return (int)GetValue(SelectionLengthProperty); } 
      set { SetValue(SelectionLengthProperty, value); } 
     } 

     // Using a DependencyProperty as the backing store for SelectionLength. This enables animation, styling, binding, etc... 
     public static readonly DependencyProperty SelectionLengthProperty = 
      DependencyProperty.Register("SelectionLength", typeof(int), typeof(MvvmTextEditor), new PropertyMetadata(0,SelectionLengthPropertyChanged)); 


     private static void SelectionLengthPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
     { 
      var textEditor = obj as MvvmTextEditor; 

      textEditor.SelectionLength = e.NewValue; 
     } 
+0

我現在就試試這個,送還給你。感謝您的時間... – MoonKnight

+0

您是否在構造函數中註冊'SelectionLengthPropertyChanged'? – MoonKnight

+0

不,我很抱歉。您正在將其註冊到'Dependencyproperty''元數據'中。在我的例子中忘了這個。另外:嘗試直接設置值到控制。這將是我猜測的最佳方式。 –

1

如果你仍然開放,這是另一個答案。由於SelectionLength已經被定義爲基類的依賴屬性,而不是創建派生類(或者將已經存在的屬性添加到派生類),所以我會使用附加屬性來實現相同的功能。

關鍵是要使用System.ComponentModel.DependencyPropertyDescriptor來訂閱已存在的SelectionLength依賴項屬性的change事件,然後在事件處理程序中執行所需的操作。

示例代碼如下:

public class SomeBehavior 
{ 
    public static readonly DependencyProperty IsEnabledProperty 
     = DependencyProperty.RegisterAttached("IsEnabled", 
     typeof(bool), typeof(SomeBehavior), new PropertyMetadata(OnIsEnabledChanged)); 

    public static void SetIsEnabled(DependencyObject dpo, bool value) 
    { 
     dpo.SetValue(IsEnabledProperty, value); 
    } 

    public static bool GetIsEnabled(DependencyObject dpo) 
    { 
     return (bool)dpo.GetValue(IsEnabledProperty); 
    } 

    private static void OnIsEnabledChanged(DependencyObject dpo, DependencyPropertyChangedEventArgs args) 
    { 
     var editor = dpo as TextEditor; 
     if (editor == null) 
      return; 

     var dpDescriptor = System.ComponentModel.DependencyPropertyDescriptor.FromProperty(TextEditor.SelectionLengthProperty,editor.GetType()); 
     dpDescriptor.AddValueChanged(editor, OnSelectionLengthChanged); 
    } 

    private static void OnSelectionLengthChanged(object sender, EventArgs e) 
    { 
     var editor = (TextEditor)sender; 
     editor.Select(editor.SelectionStart, editor.SelectionLength); 
    } 
} 

下面的XAML:

<Controls:TextEditor Behaviors:SomeBehavior.IsEnabled="True"> 
    </Controls:TextEditor>