Reputation: 313
My goal is to create add Text property to RichTextBox. I created Attached Property and set binding to ViewModel's property. Unfortunately changing text in RichTextBox doesn't update underlying property.
Here is my code:
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()
{
}
}
}
I know that Callback throws and exception but my goal here is to just see under the debugger that this callback is invoked. Then I add correct implementation.
EDIT: I think I missed important note about my issue. When I update TextToSearchArg property from code everything works correctly. The only problem is that when I set some text in RichTextBox underlying property is not updated.
What am I missing? Thanks a lot in advance.
Upvotes: 3
Views: 2881
Reputation: 64278
Nothing in your code shows that the Attached property is bound to the RichTextBox
events, hence it won't ever be called if the content/text in RichTextBox
changes.
You'd need to subscribe to the 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);
}
}
Edit:
In case you want to listen to another control's Dependency/Attached Property changes, use
DependencyPropertyDescriptor.FromProperty(ControlClassName.DesiredPropertyProperty, typeof(ControlClassName)).AddValueChanged(dependencyObject, OnDesiredPropertyChanged);
Where...
ControlClassName
is the class containing the Dependency Property (i.e. RichTextBox
in your case or the class where the Dependency/Attached Property is definedis the name of your property (i.e.
TextProperty` dependencyObject
is the instance of object where the DesiredPropertyProperty
is set onOnDesiredPropertyChanged
method to call when the property value changesOn a side note:
You should have Code-Behind in the view. There is no requirement that Dependency Properties or Attached Properties have to be defined inside the same class as the are meant for.
Code behind should only be used, if it's an reusable User Control but the naming of your class suggest it's not a User Control (even though it derives form User Control) but a View.
A view is application specific and can't be reused outside that specific app and is only meant to display a certain content. If you make a "LoginControl" then it it can be made to be reusable in other. A "LoginView" on other side doesn't suggest re-usability.
Upvotes: 1
Reputation: 4611
Maybe
Mode=TwoWay, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged
on the binding missing?
Upvotes: 0