c# - WPF 将 ViewModel 属性绑定(bind)到附加属性

标签 c# wpf xaml mvvm

我的目标是创建向 RichTextBox 添加 Text 属性。我创建了附加属性并将绑定(bind)设置为 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()
        {

        }            
    }
}

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

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

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

最佳答案

您的代码中没有任何内容表明 Attached 属性绑定(bind)到 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);

哪里...

  • ControlClassName 是包含依赖属性的类(即您的情况下的 RichTextBox 或定义依赖/附加属性的类
  • 'DesiredPropertyProperty是您的属性的名称(即TextProperty`
  • dependencyObject 是设置了 DesiredPropertyProperty 的对象实例
  • OnDesiredPropertyChanged 属性值改变时调用的方法

旁注:

您应该在 View 中有代码隐藏。没有要求必须在同一个类中定义依赖属性或附加属性。

仅当它是可重用的用户控件时才应使用代码隐藏,但您的类的命名表明它不是用户控件(即使它派生自用户控件)而是 View 。

View 是特定于应用程序的,不能在该特定应用程序之外重复使用,只能显示特定内容。如果你制作一个“LoginControl”,那么它可以在其他地方重复使用。另一边的“LoginView”并不意味着可重用性。

关于c# - WPF 将 ViewModel 属性绑定(bind)到附加属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30404060/

相关文章:

c# - 在 StackPanel 中为子级设置动画 - WPF (C#)

.net - WPF不同的窗口图标和任务栏图标

wpf - wpf/xaml 中的仅角边框

c# - 当边框有圆角时,如何使元素看起来像 "below"边框,但 "above"边框的内容?

c# - 如何动态设置和获取xaml中的标签?

c# - 在 Blazor 中,如何在动态模型中 @bind 然后触发 @onchange

c# - 简单问题 : convert a string to an image tag in c# asp.net mvc

c++ - Windows下免费商用框架中ViewBox的替换

c# - 如果同一实体包含在实体的不同集合中,如何更改实体的状态

c# - 为什么C#中没有类似Java的信号量获取多个权限?