WPF将ViewModel属性绑定到附加属性

时间:2015-05-22 18:59:49

标签: c# wpf xaml mvvm

我的目标是为RichTextBox创建添加Text属性。我创建了Attached Property并设置了对ViewModel属性的绑定。不幸的是,在RichTextBox中更改文本并不会更新底层属性。

这是我的代码:

View.cs:

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

    public static string GetText(DependencyObject obj)
    {
        return (string)obj.GetValue(TextProperty);
    }

    public static void SetText(DependencyObject obj, string value)
    {
        obj.SetValue(TextProperty, value);
    }

    public static readonly DependencyProperty TextProperty = DependencyProperty.RegisterAttached
    (
        "Text",
        typeof(string),
        typeof(KnuthMorrisPrattView),
        new FrameworkPropertyMetadata()
        {
            BindsTwoWayByDefault = true,
            PropertyChangedCallback = PropertyChangedCallback,
            CoerceValueCallback = CoerceValueCallback,
            DefaultUpdateSourceTrigger = UpdateSourceTrigger.LostFocus
        }
    );

    private static object CoerceValueCallback(DependencyObject dependencyObject, object baseValue)
    {
        throw new NotImplementedException();
    }

    private static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
    {
        throw new NotImplementedException();
    }
}

View.xaml:

<UserControl x:Class="Launcher.Views.KnuthMorrisPrattView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:views="clr-namespace:Launcher.Views"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="500"
         DataContext="{Binding KnuthMorrisPrattViewModel, Source={StaticResource MainViewModel}}">
<Grid Margin="15">
    <Grid.RowDefinitions>
        <RowDefinition Height="7*"/>
        <RowDefinition Height="3*"/>
    </Grid.RowDefinitions>
    <DockPanel Grid.Row="0">
        <Label Content="Text" DockPanel.Dock="Top"></Label>
        <RichTextBox x:Name="TextBox" views:KnuthMorrisPrattView.Text="{Binding TextToSearchArg}"/>
    </DockPanel>
    <DockPanel Grid.Row="1">
        <Label Content="Pattern" DockPanel.Dock="Top"></Label>
        <TextBox Text="{Binding PatternArg}"/>
    </DockPanel>
</Grid>

ViewModel.cs:

using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using GalaSoft.MvvmLight.CommandWpf;
using Launcher.Runners.KnuthMorrisPratt;

namespace Launcher.ViewModels
{
    public class KnuthMorrisPrattViewModel : ViewModelBase
    {
        private string _textToSearchArg;
        private string _patternArg;

        public string TextToSearchArg
        {
            get { return _textToSearchArg; }
            set
            {
                _textToSearchArg = value;
                RaisePropertyChanged();
            }
        }

        public string PatternArg
        {
            get { return _patternArg; }
            set
            {
                _patternArg = value;
                RaisePropertyChanged();
            }
        }           

        public KnuthMorrisPrattViewModel()
        {

        }            
    }
}

我知道Callback会抛出异常,但我的目标是在调试器下看到调用此回调。然后我添加正确的实现。

修改 我想我错过了关于我的问题的重要说明。当我从代码更新TextToSearchArg属性时一切正常。唯一的问题是,当我在RichTextBox中设置一些文本时,底层属性没有更新。

我错过了什么?非常感谢。

2 个答案:

答案 0 :(得分:1)

您的代码中没有任何内容表明Attached属性绑定到RichTextBox事件,因此如果RichTextBox中的内容/文本发生更改,则不会调用它。

您需要订阅RichTextBox.TextChanged event

public partial class KnuthMorrisPrattView : UserControl
{
    public KnuthMorrisPrattView()
    {
        InitializeComponent();
        this.TextBox.TextChanged += OnTextChanged;
    }

    ...

    public void OnTextChanged(object sender, TextChangedEventArgs e) 
    {
        // Get the text from the event and set your Text Property 
        string text = ...; 
        SetText(this, text);
    }
}

修改

如果您想要收听其他控件的依赖关系/附加属性更改,请使用

DependencyPropertyDescriptor.FromProperty(ControlClassName.DesiredPropertyProperty, typeof(ControlClassName)).AddValueChanged(dependencyObject, OnDesiredPropertyChanged);

WHERE ...

  • ControlClassName是包含依赖项属性的类(即您的案例中的RichTextBox或定义了依赖项/附加属性的类
  • 'DesiredPropertyProperty is the name of your property (i.e. TextProperty`
  • dependencyObject
  • 上设置DesiredPropertyProperty的对象实例
  • OnDesiredPropertyChanged在属性值更改时调用的方法

旁注:

您应该在视图中使用Code-Behind。不要求必须在与所针对的同一类中定义依赖项属性或附加属性。

只应使用代码隐藏,如果它是可重用的用户控件,但类的命名表明它不是用户控件(即使它从用户控件派生形式),而是视图。

视图是特定于应用程序的,不能在该特定应用程序之外重复使用,仅用于显示特定内容。如果您创建一个“LoginControl”,那么它可以在其他中重复使用。另一方面的“LoginView”并不表示可重用性。

答案 1 :(得分:0)

也许

Mode=TwoWay, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged 

关于绑定缺失?