4

我创建了一个TextEditor继承自 AvalonEdit 的自定义控件。我这样做是为了方便使用此编辑器控件使用 MVVM 和 Caliburn Micro。[为显示目的而削减]MvvTextEditor类是

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}"/>

我的问题是SelectionLengthSelectionStart但让我们现在只考虑长度,因为问题是一样的)。如果我用鼠标选择了一些东西,从视图到我的视图模型的绑定效果很好。现在,我编写了一个查找和替换实用程序,我想从后面的代码中设置SelectionLength(在控件中具有get并且set可用)。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 本身[这会带来它自己的问题]?

谢谢你的时间。

4

3 回答 3

1

这是因为Getterand Setterfrom aDependencyProperty只是一个 .NET Wrapper。框架将使用GetValueandSetValue本身。

您可以尝试PropertyChangedCallback从您DependencyProperty那里访问并设置正确的值。

 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;
        }
于 2014-06-02T08:02:45.117 回答
1

如果您仍然开放,这是另一个答案。由于 SelectionLength 已经定义为基类上的依赖属性,而不是创建派生类(或将已经存在的属性添加到派生类),我将使用附加属性来实现相同的功能。

关键是使用 System.ComponentModel.DependencyPropertyDescriptor 订阅已经存在的 SelectionLength 依赖属性的更改事件,然后在事件处理程序中执行所需的操作。

下面的示例代码:

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>
于 2014-06-03T23:01:44.560 回答
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); }
}

很抱歉浪费了任何时间。我希望这对其他人有帮助...

于 2014-06-02T10:17:02.047 回答