自动锁定类
我编写了一个名为“AutomaticLock”的类,它具有继承附加的“DoLock”属性。
将“DoLock”属性设置为true,将重新设计所有TextBoxes ComboBoxes、CheckBoxes等,使它们成为TextBlocks、不可编辑的CheckBoxes等。我的代码设置了其他附加属性,可以指定在锁定(“查看”)模式下使用任意模板的控件,永远不应自动锁定的控件等。
因此,相同的视图可以很容易地用于编辑和查看。设置单个属性即可来回切换,并且它是完全可自定义的,因为视图中的任何控件都可以针对“DoLock”属性触发,以任意方式更改其外观或行为。
实现代码
这是代码:
public class AutomaticLock : DependencyObject
{
Control _target;
ControlTemplate _originalTemplate;
public static bool GetEnabled(DependencyObject obj) { return (bool)obj.GetValue(EnabledProperty); }
public static void SetEnabled(DependencyObject obj, bool value) { obj.SetValue(EnabledProperty, value); }
public static readonly DependencyProperty EnabledProperty = DependencyProperty.RegisterAttached("Enabled", typeof(bool), typeof(AutomaticLock), new FrameworkPropertyMetadata
{
PropertyChangedCallback = OnLockingStateChanged,
});
public static ControlTemplate GetLockTemplate(DependencyObject obj) { return (ControlTemplate)obj.GetValue(LockTemplateProperty); }
public static void SetLockTemplate(DependencyObject obj, ControlTemplate value) { obj.SetValue(LockTemplateProperty, value); }
public static readonly DependencyProperty LockTemplateProperty = DependencyProperty.RegisterAttached("LockTemplate", typeof(ControlTemplate), typeof(AutomaticLock), new FrameworkPropertyMetadata
{
PropertyChangedCallback = OnLockingStateChanged,
});
public static bool GetDoLock(DependencyObject obj) { return (bool)obj.GetValue(DoLockProperty); }
public static void SetDoLock(DependencyObject obj, bool value) { obj.SetValue(DoLockProperty, value); }
public static readonly DependencyProperty DoLockProperty = DependencyProperty.RegisterAttached("DoLock", typeof(bool), typeof(ControlTemplate), new FrameworkPropertyMetadata
{
Inherits = true,
PropertyChangedCallback = OnLockingStateChanged,
});
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public static AutomaticLock GetCurrentLock(DependencyObject obj) { return (AutomaticLock)obj.GetValue(CurrentLockProperty); }
public static void SetCurrentLock(DependencyObject obj, AutomaticLock value) { obj.SetValue(CurrentLockProperty, value); }
public static readonly DependencyProperty CurrentLockProperty = DependencyProperty.RegisterAttached("CurrentLock", typeof(AutomaticLock), typeof(AutomaticLock));
static void OnLockingStateChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
AutomaticLock current = GetCurrentLock(obj);
bool shouldLock = GetDoLock(obj) && (GetEnabled(obj) || GetLockTemplate(obj)!=null);
if(shouldLock && current==null)
{
if(!(obj is Control)) throw new InvalidOperationException("AutomaticLock can only be used on objects derived from Control");
new AutomaticLock((Control)obj).Attach();
}
else if(!shouldLock && current!=null)
current.Detach();
}
AutomaticLock(Control target)
{
_target = target;
}
void Attach()
{
_originalTemplate = _target.Template;
_target.Template = GetLockTemplate(_target) ?? SelectDefaultLockTemplate();
SetCurrentLock(_target, this);
}
void Detach()
{
_target.Template = _originalTemplate;
_originalTemplate = null;
SetCurrentLock(_target, null);
}
ControlTemplate SelectDefaultLockTemplate()
{
for(Type type = _target.GetType(); type!=typeof(object); type = type.BaseType)
{
ControlTemplate result =
_target.TryFindResource(new ComponentResourceKey(type, "AutomaticLockTemplate")) as ControlTemplate ??
_target.TryFindResource(new ComponentResourceKey(typeof(AutomaticLock), type.Name)) as ControlTemplate;
if(result!=null) return result;
}
return null;
}
}
这段代码将允许您根据控件自动锁定模板或使用默认模板来指定控件的自动锁定模板。默认模板可以在包含AutomaticLock类的程序集、应用于锁定模板的自定义控件所在的程序集或者视觉树中的本地资源(包括应用程序资源)中定义。
如何定义AutomaticLock模板
WPF标准控件的默认模板在ResourceDictionary中定义,该ResourceDictionary合并到Themes/Generic.xaml中,位于包含AutomaticLock类的程序集中。例如,此模板会使所有TextBox在锁定时变成TextBlocks:
<ControlTemplate TargetType="{x:Type TextBox}"
x:Key="{ComponentResourceKey ResourceId=TextBox, TypeInTargetAssembly={x:Type lc:AutomaticLock}}">
<TextBlock Text="{TemplateBinding Text}" />
</ControlTemplate>
自定义控件的默认模板可以在包含自定义控件的程序集中定义,在其Themes/Generic.xaml中合并ResourceDictionary。在这种情况下,ComponentResourceKey是不同的,例如:
<ControlTemplate TargetType="{x:Type prefix:MyType}"
x:Key="{ComponentResourceKey ResourceId=AutomaticLockTemplate, TypeInTargetAssembly={x:Type prefix:MyType}}">
...
如果一个应用程序想要覆盖特定类型的标准AutomaticLock模板,它可以在其App.xaml、Window XAML、UserControl XAML或单个控件的ResourceDictionary中放置一个自动锁定模板。在每种情况下,ComponentResourceKey应该与自定义控件的指定方式相同:
x:Key="{ComponentResourceKey ResourceId=AutomaticLockTemplate, TypeInTargetAssembly={x:Type prefix:MyType}}"
最后,可以通过设置其
AutomaticLock.LockTemplate
属性来将自动锁定模板应用于单个控件。
如何在您的UI中使用AutomaticLock:
要使用自动锁定:
1. 在任何应自动锁定的控件上设置
AutomaticLock.Enabled="True"
。这可以在样式或直接在各个控件上完成。它启用控件上的锁定,但不会导致控件实际上被锁定。
2. 当您想要锁定时,在顶级控件(窗口、视图、UserControl等)上设置
AutomaticLock.DoLock="True"
,以便在您需要自动锁定实际发生时进行操作。您可以将
AutomaticLock.DoLock
绑定到复选框或菜单项,或者在代码中进行控制。
一些有效切换视图和编辑模式的技巧:
即使视图和编辑模式有很大的区别,使用此AutomaticLock类也非常适合切换两者。我有几种不同的构建视图的技术,以适应编辑时的布局差异。其中一些是:
1. 通过将它们的模板或自动锁定模板设置为空模板,使控件在编辑或查看模式下不可见。例如,假设“年龄”在视图模式下位于布局顶部,在编辑模式下位于底部。在两个位置都添加一个“年龄”文本框。在顶部的文本框中将模板设置为空模板,以便在编辑模式下不显示它。在底部的文本框中将
AutomaticLockTemplate
设置为空模板。现在只有一个会显示出来。
2. 使用ContentControl替换包围内容的边框、布局面板、按钮等,而不影响内容。ContentControl的模板具有编辑模式下的周围边框、面板、按钮等。它还具有一个自动锁定模板,其中包含视图模式版本。
3. 使用Control替换视图中的矩形部分(我实际上是指“Control”类的对象,而不是子类)。同样,您可以将编辑模式版本放入模板中,并将视图模式版本放入
AutomaticLockTemplate
中。
4. 使用带有额外自动大小行和列的Grid。使用AutomaticLock.DoLock属性上的触发器来更新Grid内项目的Row、Column、RowSpan和ColumnSpan属性。例如,您可以通过将其Grid.Row从6更改为0来将包含“年龄”控件的面板移动到顶部。
5. 触发DoLock以对您的项目应用LayoutTranform或RenderTransform,或设置其他属性,如宽度和高度。如果您想要在编辑模式下使事物变大,或者如果您想要使TextBox更宽并将按钮移动到其边缘旁边,则这非常有用。
请注意,您可以在整个视图中使用选项#3(带有编辑和查看模式的控制对象)。如果编辑和查看模式完全不同,则可以这样做。在这种情况下,AutomaticLock仍然为您提供了手动设置两个模板的便利。它将如下所示:
<Control>
<Control.Template>
<ControlTemplate>
<!-- Edit mode view here -->
</ControlTemplate>
</Control.Template>
<lib:AutomaticLock.LockTemplate>
<ControlTemplate>
<!-- View mode view here -->
</ControlTemplate>
</lib:AutomaticLock.LockTemplate>
</Control>
一般来说,在编辑模式和查看模式之间微调几个位置和其他细节更容易,并且可以提高用户体验,因为用户会有一致的布局。但是,如果您需要完全替换,则AutomaticLock也具备这种功能。
public static readonly DependencyProperty DoLockProperty = DependencyProperty.RegisterAttached("DoLock", typeof(bool), typeof(AutomaticLock)...
- Scott O.new AutomaticLock((Control)obj).Attach();
,其中分配了新的引用。 - AbderrahimDz24