我在WPF / XAML中有一个TextBox的子类,我希望对它应用与我所有其他TextBox实例相同的样式。我定义了以下样式
<Style TargetType="TextBox" x:Key="basicTextBox" >
<Setter Property="Controls:TextBoxBehaviours.UpdateWhenEnterPressed" Value="True"/>
<Setter Property="Controls:TextBoxBehaviours.SelectAllWhenEnterPressed" Value="True"/>
<Setter Property="Controls:TextBoxBehaviours.SelectAllOnFocus" Value="True"/>
</Style>
和一个TextBoxBehaviours类来实现这些
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Reactive.Linq;
namespace Weingartner.Controls
{
public static class TextBoxBehaviours
{
static TextBoxBehaviours()
{}
#region Binding Support
private static Dictionary<Tuple<TextBox,string>, IDisposable> Bindings
= new Dictionary<Tuple<TextBox,string>, IDisposable>();
private static void Bind(TextBox tb, string key, IDisposable d)
{
Bindings[Tuple.Create(tb, key)] = d;
}
private static void UnBind(TextBox tb, string key)
{
var t = Tuple.Create(tb, key);
if (Bindings.ContainsKey(t))
{
var d = Bindings[t];
Bindings.Remove(t);
d.Dispose();
}
}
#endregion
static UIPropertyMetadata CreateMeta<T>(bool defaultValue, Action<T,DependencyPropertyChangedEventArgs> fn)
where T : DependencyObject
{
return new UIPropertyMetadata(defaultValue, (o, e) =>{
var t = o as T;
if (t == null)
{
return;
}
fn(t, e);
});
}
#region Update When Enter Pressed
public static readonly DependencyProperty
UpdateWhenEnterPressedProperty =
DependencyProperty.RegisterAttached
( "UpdateWhenEnterPressed"
, typeof(bool)
, typeof(TextBoxBehaviours)
, CreateMeta<TextBox>(false, SetupUpdateOnEnterPressed));
public static void
SetUpdateWhenEnterPressed
( TextBox dp
, bool value)
{
dp.SetValue(UpdateWhenEnterPressedProperty, value);
}
public static bool
GetUpdateWhenEnterPressed
( TextBox dp)
{
return (bool)dp.GetValue(UpdateWhenEnterPressedProperty);
}
private static void
SetupUpdateOnEnterPressed
( TextBox element
, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue)
{
var sub = element
.PreviewKeyDownObserver()
.Where(x=>x.EventArgs.Key==Key.Enter)
.Subscribe(x=>DoUpdateSource(element));
Bind(element, "KeyEnter", sub);
}else{
UnBind(element, "KeyEnter");
}
}
static void DoUpdateSource(TextBox source)
{
BindingExpression binding = BindingOperations.GetBindingExpression(source, TextBox.TextProperty);
if (binding != null)
{
binding.UpdateSource();
}
}
#endregion
#region SelectAll When Enter Pressed
public static readonly DependencyProperty
SelectAllWhenEnterPressedProperty =
DependencyProperty.RegisterAttached
( "SelectAllWhenEnterPressed"
, typeof(bool)
, typeof(TextBoxBehaviours)
, CreateMeta<TextBox>(false, SetupSelectAllOnEnterPressed));
public static void
SetSelectAllWhenEnterPressed
( TextBox dp
, bool value)
{
dp.SetValue(SelectAllWhenEnterPressedProperty, value);
}
public static bool
GetSelectAllWhenEnterPressed
( TextBox dp)
{
return (bool)dp.GetValue(SelectAllWhenEnterPressedProperty);
}
private static void
SetupSelectAllOnEnterPressed
( TextBox element
, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue)
{
var sub = element
.PreviewKeyDownObserver()
.Where(x=>x.EventArgs.Key==Key.Enter)
.Subscribe(x=>element.SelectAll());
Bind(element, "KeyEnterSelectAll", sub);
}else{
UnBind(element, "KeyEnterSelectAll");
}
}
#endregion
#region Select All On Focus
public static readonly DependencyProperty
SelectAllOnFocusProperty =
DependencyProperty.RegisterAttached
( "SelectAllOnFocus"
, typeof(bool)
, typeof(TextBoxBehaviours)
, CreateMeta<TextBox>(false, SetupSelectAllOnFocus));
public static void
SetSelectAllOnFocus
( TextBox dp
, bool value)
{
dp.SetValue(SelectAllOnFocusProperty, value);
}
public static bool
GetSelectAllOnFocus
( TextBox dp)
{
return (bool)dp.GetValue(SelectAllOnFocusProperty);
}
private static void
SetupSelectAllOnFocus
( TextBox element
, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue)
{
Bind(element, "Focus", element.GotFocusObserver().Subscribe(x => element.SelectAll()));
}else{
UnBind(element, "Focus");
}
}
#endregion
}
}
在我一直在做的XAML文件中
<Style TargetType="TextBox" BasedOn="{StaticResource basicTextBox}"/>
以及所有后面的TextBoxes获得我想要的behviour。鉴于我的子类也是一个TextBox类,我认为这些也会得到行为,但事实并非如此。我尝试通过扩展样式来明确
<Style TargetType="TextBox" BasedOn="{StaticResource basicTextBox}"/>
<Style TargetType="Controls:EditForLength">
<Setter Property="Controls:TextBoxBehaviours.UpdateWhenEnterPressed" Value="True"/>
<Setter Property="Controls:TextBoxBehaviours.SelectAllWhenEnterPressed" Value="True"/>
<Setter Property="Controls:TextBoxBehaviours.SelectAllOnFocus" Value="True"/>
</Style>
但是我收到错误,告诉我EditForLength
System.ArgumentException occurred
HResult=-2147024809
Message=Item has already been added. Key in dictionary: 'Weingartner.Controls.EditForLength' Key being added: 'Weingartner.Controls.EditForLength'
Source=mscorlib
StackTrace:
at System.Collections.Hashtable.Insert(Object key, Object nvalue, Boolean add)
InnerException:
因此,在通过父类的样式安装的摘要行为中,不会传播给子类实例,但是当尝试添加另一种针对子类的样式时,会出现一些字典错误。
注意我已经尝试过对EditForLength
控件实例的行为明确表示他们正常工作。我无法通过样式安装行为。
更新
发现即使所有重要的位都出现错误 除了样式声明被注释掉
<!--<Style TargetType="TextBox" BasedOn="{StaticResource basicTextBox}"/>-->
<Style TargetType="Controls:EditForLength">
<!--
<Setter Property="Controls:TextBoxBehaviours.UpdateWhenEnterPressed" Value="True"/>
<Setter Property="Controls:TextBoxBehaviours.SelectAllWhenEnterPressed" Value="True"/>
<Setter Property="Controls:TextBoxBehaviours.SelectAllOnFocus" Value="True"/>
-->
</Style>
答案 0 :(得分:0)
关于异常:您似乎已经在字典(或其合并的字典)中添加了此样式 - 尝试搜索它,我相信您会找到具有相同密钥的样式。
关于隐式样式:它们不适用于目标类型的子类(尝试想象它们是否应用 - 如果您为FrameworkElement创建了隐式样式 - 大部分控件的布局将被破坏)