[英]Change Tag property of TextBox that resides in ControlTemplate of ComboBox
我想在IsEditable="true"
时更改WPF ComboBox
内的TextBox
的Tag
属性。
我试过的
<Style TargetType="{x:Type ComboBox}">
<Setter Property="TextElement.Tag" Value="MyValue" />
</Style>
上面的代码似乎无效。
我不想要的:
我不想仅针对单个属性重新定义ComboBox的ControlTemplate
。
为什么要更改ComboBox
内的TextBox
的Tag
而不是使用ComboBox
的Tag
属性:为什么我按如下所示使用EnterKeyTraversal
类:
EnterKeyTraversal.cs
:
public class EnterKeyTraversal
{
public static bool GetIsEnabled(DependencyObject obj)
{
return (bool)obj.GetValue(IsEnabledProperty);
}
public static void SetIsEnabled(DependencyObject obj, bool value)
{
obj.SetValue(IsEnabledProperty, value);
}
static void ue_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
var ue = e.OriginalSource as FrameworkElement;
DependencyObject dep = ue;
while (!(dep == null || dep is DataGrid))
{
dep = VisualTreeHelper.GetParent(dep);
}
if (!(ue is Button || ue is ListBoxItem || dep is DataGrid))
{
if (e.Key == Key.Enter)
{
if (!(ue.Tag != null && ue.Tag.ToString() == "IgnoreEnterKeyTraversal"))
{
e.Handled = true;
ue.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
}
}
}
private static void ue_Unloaded(object sender, RoutedEventArgs e)
{
var ue = sender as FrameworkElement;
if (ue == null) return;
ue.Unloaded -= ue_Unloaded;
ue.PreviewKeyDown -= ue_PreviewKeyDown;
}
public static readonly DependencyProperty IsEnabledProperty =
DependencyProperty.RegisterAttached("IsEnabled", typeof(bool),
typeof(EnterKeyTraversal), new UIPropertyMetadata(false, IsEnabledChanged));
static void IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ue = d as FrameworkElement;
if (ue == null) return;
if ((bool)e.NewValue)
{
ue.Unloaded += ue_Unloaded;
ue.PreviewKeyDown += ue_PreviewKeyDown;
}
else
{
ue.PreviewKeyDown -= ue_PreviewKeyDown;
}
}
}
在MainWindow
:
<Window ....... helpers:EnterKeyTraversal.IsEnabled="True">
........
</Window>
在其他页面上:
<TextBox Tag="IgnoreEnterKeyTraversal" /> <!-- Works Fine -->
<ComboBox Tag="IgnoreEnterKeyTraversal" /><!-- Not Working -->
所以,我想如果我更改ComboBox
内TextBox
的Tag
,就可以停止Enter的遍历
在深入研究EnterKeyTraversal之后,我找到了解决方案:
这是我的新EnterKeyTraversal.cs
public class EnterKeyTraversal
{
public static bool GetIsEnabled(DependencyObject obj)
{
return (bool)obj.GetValue(IsEnabledProperty);
}
public static void SetIsEnabled(DependencyObject obj, bool value)
{
obj.SetValue(IsEnabledProperty, value);
}
static void ue_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
var ue = e.OriginalSource as FrameworkElement;
DependencyObject dep = ue;
while (!(dep == null || dep is DataGrid))
{
dep = VisualTreeHelper.GetParent(dep);
}
DependencyObject combo = ue;
while (!(combo == null || combo is ComboBox))
{
combo = VisualTreeHelper.GetParent(combo);
}
if (!(ue is Button || ue is ListBoxItem || dep is DataGrid || (combo is ComboBox && ((ComboBox)combo).Tag.ToString() == "IgnoreEnterKeyTraversal")))
{
if (e.Key == Key.Enter)
{
if (!(ue.Tag != null && ue.Tag.ToString() == "IgnoreEnterKeyTraversal"))
{
e.Handled = true;
ue.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
}
}
}
private static void ue_Unloaded(object sender, RoutedEventArgs e)
{
var ue = sender as FrameworkElement;
if (ue == null) return;
ue.Unloaded -= ue_Unloaded;
ue.PreviewKeyDown -= ue_PreviewKeyDown;
}
public static readonly DependencyProperty IsEnabledProperty =
DependencyProperty.RegisterAttached("IsEnabled", typeof(bool),
typeof(EnterKeyTraversal), new UIPropertyMetadata(false, IsEnabledChanged));
static void IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ue = d as FrameworkElement;
if (ue == null) return;
if ((bool)e.NewValue)
{
ue.Unloaded += ue_Unloaded;
ue.PreviewKeyDown += ue_PreviewKeyDown;
}
else
{
ue.PreviewKeyDown -= ue_PreviewKeyDown;
}
}
}
我在回答您的第一个问题: 我想在IsEditable =“ true”时更改WPF ComboBox内的TextBox的Tag属性。
由于您尝试更新在ComboBox
的ControlTemplate
中定义的control's
属性,因此style
, Binding
或Trigger
无法正常工作。 所以我用了这个辅助类:
助手类:
public class ComboBoxBehave
{
public static string GetApplyTag(DependencyObject obj)
{
return (string)obj.GetValue(ApplyTagProperty);
}
public static void SetApplyTag(DependencyObject obj, string value)
{
obj.SetValue(ApplyTagProperty, value);
}
// Using a DependencyProperty as the backing store for ApplyTag. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ApplyTagProperty =
DependencyProperty.RegisterAttached("ApplyTag", typeof(string), typeof(ComboBoxBehave), new UIPropertyMetadata(null, ApplyTagChanged));
private static void ApplyTagChanged(DependencyObject DO, DependencyPropertyChangedEventArgs e)
{
var combo = DO as ComboBox;
if (combo != null)
{
combo.Loaded += new RoutedEventHandler(combo_Loaded);
}
}
static void combo_Loaded(object sender, RoutedEventArgs e)
{
var combo = sender as ComboBox;
if (combo != null)
{
var text = FindChild<TextBox>(sender as DependencyObject, "PART_EditableTextBox");
if (text != null)
{
text.Tag = GetApplyTag(combo);
}
}
}
public static T FindChild<T>(DependencyObject parent, string childName)
where T : DependencyObject
{
// Confirm parent and childName are valid.
if (parent == null) return null;
T foundChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
// If the child is not of the request child type child
T childType = child as T;
if (childType == null)
{
// recursively drill down the tree
foundChild = FindChild<T>(child, childName);
// If the child is found, break so we do not overwrite the found child.
if (foundChild != null) break;
}
else if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as FrameworkElement;
// If the child's name is set for search
if (frameworkElement != null && frameworkElement.Name == childName)
{
// if the child's name is of the request name
foundChild = (T)child;
break;
}
}
else
{
// child element found.
foundChild = (T)child;
break;
}
}
return foundChild;
}
}
XAML:
<ComboBox Width="200" Name="cmbBox1" IsEditable="True" >
<ComboBox.Style>
<Style TargetType="ComboBox">
<Style.Triggers>
<Trigger Property="IsEditable" Value="True">
<Setter Property="local:ComboBoxBehave.ApplyTag" Value="IgnoreEnterKeyTraversal"/>
</Trigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
并将TextBox's
Tag设置为IgnoreEnterKeyTraversal
,再加上一些通用代码,可以将同一类用于不同的控件。
您可以考虑创建自己的ComboBox
,如下所示:
public class ComboBox : System.Windows.Controls.ComboBox
{
public static readonly DependencyProperty TextBoxTagProperty =
DependencyProperty.Register("TextBoxTag", typeof(object), typeof(ComboBox), new UIPropertyMetadata(null, new PropertyChangedCallback(OnTextBoxTagChanged)));
public object TextBoxTag
{
get { return (object)GetValue(TextBoxTagProperty); }
set { SetValue(TextBoxTagProperty, value); }
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
FrameworkElement frameworkElement = GetTemplateChild("PART_EditableTextBox") as FrameworkElement;
frameworkElement.Tag = TextBoxTag;
}
private static void OnTextBoxTagChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
{
ComboBox comboBox = d as ComboBox;
FrameworkElement frameworkElement = comboBox.GetTemplateChild("PART_EditableTextBox") as FrameworkElement;
frameworkElement.Tag = args.NewValue;
}
}
然后在您的XAML中:
<local:ComboBox IsEditable="True" Tag="combobox tag" TextBoxTag="edit textbox tag" />
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.