如何解决设计模式-WPF自动将AttachedProperty添加到父级
|| 我已经创建了一个自定义UserControl,它是某种虚拟键盘按钮。我正在寻找以下功能: 任何面板都应包含其所有键盘按钮子项的集合。 也是该面板的子级的任何其他控件都应该能够枚举其父级的键盘按钮。 在功能上实现这不是大问题。我可以创建类型为List的Attached-DependencyProperty并手动管理此列表。这种方法的问题是,它很容易出错并且不方便。 是否有可能在创建时自动将键盘按钮附加到父级的AttachedProperty?解决方法
如您所述,维护列表容易出错-您需要使其与WPF可视树保持同步。除了维护列表之外,您还可以从给定的根目录遍历可视树。在您的情况下,听起来根是
Panel
。
遍历视觉树非常容易。这篇文章展示了一些例子。我认为与此相关的一个是:
public static IEnumerable<DependencyObject> GetVisualTree(this DependencyObject element)
{
int childrenCount = VisualTreeHelper.GetChildrenCount(element);
for (int i = 0; i < childrenCount; i++)
{
var visualChild = VisualTreeHelper.GetChild(element,i);
yield return visualChild;
foreach (var visualChildren in GetVisualTree(visualChild))
{
yield return visualChildren;
}
}
}
这将对给定的DependencyObject
的所有视觉子对象进行深度优先遍历。因此,对于任何给定的Panel
,您都可以调用此方法。由于它是IEnumerable
,因此您可以使用LINQ将结果过滤到自定义UserControl。
对于您的其他要求(\“其他任何也是该面板的孩子的控件也应该能够枚举其父的键盘按钮\”):给一个孩子a0ѭ,向上走视觉树查找第一个Panel
并使用相同的过程来获取所有相关的孩子。
如果您确实需要将其作为ѭ7binding(例如用于数据绑定),我认为您可以将其设置为只读,并且仍在getter中使用Visual Tree Traversal方法,但是我不确定。
,我已经为我的问题创建了一个很好的解决方案。以下代码显示了我的实现:
// KeyboardButton.cs
/// <remarks>
/// This class does contain a lot of more code which isn\'t related to the actual problem.
/// </remarks>
public partial class KeyboardButton
{
[DefaultValue(Key.NoName)]
public Key EmulatedKey { get; set; }
}
// KeyboardPanel.cs
public class KeyboardButtonCollection : Collection<KeyboardButton> { }
public static class KeyboardPanel
{
internal const string ButtonsPropertyName = \"Buttons\";
static KeyboardPanel()
{
ButtonsProperty = DependencyProperty.RegisterAttached
(
ButtonsPropertyName,typeof(KeyboardButtonCollection),typeof(KeyboardPanel),new UIPropertyMetadata(null,OnButtonsChanged)
);
}
public static KeyboardButtonCollection GetButtons(DependencyObject dependencyObject)
{
return (KeyboardButtonCollection)dependencyObject.GetValue(ButtonsProperty);
}
public static void SetButtons(DependencyObject dependencyObject,KeyboardButtonCollection value)
{
dependencyObject.SetValue(ButtonsProperty,value);
}
public static bool IsKeyboardPanel(DependencyObject dependencyObject)
{
return GetButtons(dependencyObject).Count != 0;
}
public static readonly DependencyProperty ButtonsProperty;
private static void OnButtonsChanged(DependencyObject dependencyObject,DependencyPropertyChangedEventArgs e)
{
bool isSupportedType = true;
if (dependencyObject is Panel)
{
var panel = (Panel)dependencyObject;
foreach (var button in (KeyboardButtonCollection)e.NewValue)
panel.Children.Add(button);
}
else
isSupportedType = false;
if (!isSupportedType)
throw new NotSupportedException(string.Format(\"Type {0} is not supported as KeyboardPanel.\",dependencyObject.GetType()));
}
}
<!-- MainWindow.xaml -->
<Grid>
<controls:KeyboardPanel.Buttons>
<controls:KeyboardButtonCollection>
<controls:KeyboardButton Content=\"Enter\" EmulatedKey=\"Enter\"/>
<controls:KeyboardButton Grid.Row=\"1\" Content=\"Some Key\"/>
<controls:KeyboardButton Grid.Row=\"2\" Content=\"Another Key\"/>
</controls:KeyboardButtonCollection>
</controls:KeyboardPanel.Buttons>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Grid.Row=\"3\" Content=\"Test\" Loaded=\"Button_Loaded\"/>
</Grid>
// MainWindow.xaml.cs
public partial class MainWindow : Window
{
private void Button_Loaded(object sender,RoutedEventArgs e)
{
var button = (Button)sender;
if (KeyboardPanel.IsKeyboardPanel(button.Parent))
{
var enterButton = KeyboardPanel.GetButtons(button.Parent)
.FirstOrDefault(b => b.EmulatedKey == Key.Enter);
if (enterButton != null)
MessageBox.Show(\"KeyboardPanel contains an EnterButton\");
else
MessageBox.Show(\"KeyboardPanel doesn\'t contain an EnterButton\");
}
}
}
我通常不是在.NET中编程,而是-不时-我被“强迫”使用它来创建一些工具。但是,你们中的有些人可能知道如何消除此代码的弱点:它不支持VisualStudio或Expression Blend Designer。因此,控件无法在设计时修改甚至看不到。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。