使用MVVM的WPF绑定失败
本文关键字:绑定 失败 WPF MVVM 使用 | 更新日期: 2023-09-27 18:04:41
我已经创建了一个继承自AvalonEdit的自定义TextEditor
控件。我这样做是为了方便使用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}"/>
我的问题是SelectionLength
(和SelectionStart
,但让我们现在只考虑长度,因为问题是相同的)。如果我用鼠标选择了一些东西,从视图到视图模型的绑定工作得很好。现在,我已经编写了一个查找和替换实用程序,我想从后面的代码设置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本身[这提出了它自己的问题]?
感谢您的宝贵时间。
这是因为来自DependencyProperty
的Getter
和Setter
只是一个。net包装器。框架将使用GetValue
和SetValue
本身。
你可以尝试从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;
}
如果你仍然开放,这里是另一个答案。由于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>
我是这样做的…
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); }
}
很抱歉浪费了你的时间。