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

本文关键字:属性 绑定 ViewModel WPF | 更新日期: 2023-09-27 17:50:24

我的目标是创建添加文本属性的RichTextBox。我创建了附加属性并设置绑定到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底层属性不更新。

我错过了什么?

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

代码中没有任何内容显示Attached属性绑定到RichTextBox事件,因此如果RichTextBox中的内容/文本发生变化,它将永远不会被调用。

你需要订阅RichTextBox.TextChanged事件。

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);

的地方……

  • ControlClassName是包含依赖属性的类(即在你的情况下RichTextBox或类的依赖/附加属性被定义
  • 'DesiredPropertyProperty is the name of your property (i.e. TextProperty '
  • dependencyObject是在
  • 上设置DesiredPropertyProperty的对象实例。
  • OnDesiredPropertyChanged方法,当属性值改变时调用

边注:

视图中应该有Code-Behind。不要求依赖属性或附加属性必须在与它们对应的同一个类中定义。

后面的代码应该只使用,如果它是一个可重用的用户控件,但你的类的命名表明它不是一个用户控件(即使它派生自用户控件),而是一个视图。

视图是特定于应用程序的,不能在特定应用程序之外重用,只能显示特定的内容。如果你做了一个"LoginControl",那么它就可以在其他地方重复使用。另一边的"LoginView"并不意味着可重用性。

可能

Mode=TwoWay, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged 

上的绑定缺失?