我发现了这个问题MVVM and the TextBox's SelectedText property。但是,我无法获得解决方案。这是我的非工作代码,我试图在第二个文本框中显示第一个文本框的选定文本。
查看:
SelectedText和Text只是我的ViewModel的字符串属性。
<TextBox Text="{Binding Path=Text, UpdateSourceTrigger=PropertyChanged}" Height="155" HorizontalAlignment="Left" Margin="68,31,0,0" Name="textBox1" VerticalAlignment="Top" Width="264" AcceptsReturn="True" AcceptsTab="True" local:TextBoxHelper.SelectedText="{Binding SelectedText, UpdateSourceTrigger=PropertyChanged, Mode=OneWayToSource}" />
<TextBox Text="{Binding SelectedText, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Height="154" HorizontalAlignment="Left" Margin="82,287,0,0" Name="textBox2" VerticalAlignment="Top" Width="239" />
TextBoxHelper
public static class TextBoxHelper
{
#region "Selected Text"
public static string GetSelectedText(DependencyObject obj)
{
return (string)obj.GetValue(SelectedTextProperty);
}
public static void SetSelectedText(DependencyObject obj, string value)
{
obj.SetValue(SelectedTextProperty, value);
}
// Using a DependencyProperty as the backing store for SelectedText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectedTextProperty =
DependencyProperty.RegisterAttached(
"SelectedText",
typeof(string),
typeof(TextBoxHelper),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, SelectedTextChanged));
private static void SelectedTextChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
TextBox tb = obj as TextBox;
if (tb != null)
{
if (e.OldValue == null && e.NewValue != null)
{
tb.SelectionChanged += tb_SelectionChanged;
}
else if (e.OldValue != null && e.NewValue == null)
{
tb.SelectionChanged -= tb_SelectionChanged;
}
string newValue = e.NewValue as string;
if (newValue != null && newValue != tb.SelectedText)
{
tb.SelectedText = newValue as string;
}
}
}
static void tb_SelectionChanged(object sender, RoutedEventArgs e)
{
TextBox tb = sender as TextBox;
if (tb != null)
{
SetSelectedText(tb, tb.SelectedText);
}
}
#endregion
}
我做错了什么?
答案 0 :(得分:1)
为了使SelectedTextChanged处理程序触发SelectedText属性必须具有初始值。如果你没有将它初始化为某个值(string.Empty作为最低限度),那么这个处理程序永远不会触发,反过来你永远不会注册tb_SelectionChanged处理程序。
答案 1 :(得分:1)
这不起作用的原因是没有引发属性更改回调(因为VM的绑定值与属性的元数据中指定的默认值相同)。但更重要的是,当所选文本设置为null时,您的行为将分离。在这种情况下,我倾向于使用另一个附加属性,该属性仅用于启用对所选文本的监视,然后可以绑定SelectedText属性。所以,像这样:
#region IsSelectionMonitored
public static readonly DependencyProperty IsSelectionMonitoredProperty = DependencyProperty.RegisterAttached(
"IsSelectionMonitored",
typeof(bool),
typeof(PinnedInstrumentsViewModel),
new FrameworkPropertyMetadata(OnIsSelectionMonitoredChanged));
[AttachedPropertyBrowsableForType(typeof(TextBox))]
public static bool GetIsSelectionMonitored(TextBox d)
{
return (bool)d.GetValue(IsSelectionMonitoredProperty);
}
public static void SetIsSelectionMonitored(TextBox d, bool value)
{
d.SetValue(IsSelectionMonitoredProperty, value);
}
private static void OnIsSelectionMonitoredChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
TextBox tb = obj as TextBox;
if (tb != null)
{
if ((bool)e.NewValue)
{
tb.SelectionChanged += tb_SelectionChanged;
}
else
{
tb.SelectionChanged -= tb_SelectionChanged;
}
SetSelectedText(tb, tb.SelectedText);
}
}
#endregion
#region "Selected Text"
public static string GetSelectedText(DependencyObject obj)
{
return (string)obj.GetValue(SelectedTextProperty);
}
public static void SetSelectedText(DependencyObject obj, string value)
{
obj.SetValue(SelectedTextProperty, value);
}
// Using a DependencyProperty as the backing store for SelectedText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectedTextProperty =
DependencyProperty.RegisterAttached(
"SelectedText",
typeof(string),
typeof(TextBoxHelper),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, SelectedTextChanged));
private static void SelectedTextChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
TextBox tb = obj as TextBox;
if (tb != null)
{
tb.SelectedText = e.NewValue as string;
}
}
static void tb_SelectionChanged(object sender, RoutedEventArgs e)
{
TextBox tb = sender as TextBox;
if (tb != null)
{
SetSelectedText(tb, tb.SelectedText);
}
}
#endregion
然后在你的XAML中,你必须将该属性添加到你的第一个TextBox:
<TextBox ... local:TextBoxHelper.IsSelectionMonitored="True" local:TextBoxHelper.SelectedText="{Binding SelectedText, Mode=OneWayToSource}" />
答案 2 :(得分:1)
这适用于我使用TextBoxHelper类。如前所述,您需要使用非null值初始化TextBoxHelper的SelectedText属性。您应该绑定到应该实现INotifyPropertyChanged的VM的字符串属性,而不是数据绑定到视图上的字符串属性(SelText)。
XAML:
<Window x:Class="TextSelectDemo.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TextSelectDemo"
Height="300" Width="300">
<StackPanel>
<TextBox local:TextBoxHelper.SelectedText="{Binding Path=SelText, Mode=TwoWay}" />
<TextBox Text="{Binding Path=SelText}" />
</StackPanel>
</Window>
代码背后:
using System.ComponentModel;
using System.Windows;
namespace TextSelectDemo
{
public partial class Window1 : Window, INotifyPropertyChanged
{
public Window1()
{
InitializeComponent();
SelText = string.Empty;
DataContext = this;
}
private string _selText;
public string SelText
{
get { return _selText; }
set
{
_selText = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("SelText"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
答案 3 :(得分:0)
您的绑定尝试将Text
的{{1}}属性绑定到TextBox
的当前数据上下文的SelectedText
属性。由于您正在使用附加属性,而不是使用数据上下文中的属性,因此您需要在绑定中提供更多信息:
TextBox
<TextBox Text="{Binding local:TextBoxHelper.SelectedText, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" ... />
与包含local
类的CLR命名空间关联的位置。
答案 4 :(得分:-1)
您需要一个普通的.net属性包装器,用于dependencyproperty,有些像:
public string SelectedText
{
set {SetSelectedText(this, value);}
...
运行时不需要它(运行时使用set / get),但设计者和编译器需要它。