Skip to content

Commit c7686bf

Browse files
committed
add zh-CN translations
1 parent 6a28b50 commit c7686bf

File tree

3 files changed

+444
-0
lines changed

3 files changed

+444
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
---
2+
id: focus
3+
title: 焦点
4+
---
5+
6+
import DirectionalNavigationScreenshot from '/img/concepts/input/directional-navigation.gif';
7+
8+
# 焦点
9+
焦点是指预期接收键盘输入的 `InputElement`,通常通过视觉指示器来区分。最熟悉的例子是包含闪烁光标的 `TextBox`,但像 `Button``Slider` 这样的非文本控件也参与焦点管理。
10+
11+
## IsFocused 和 Focusable
12+
13+
`IsFocused` 是一个只读属性,用于跟踪 `InputElement` 的焦点状态。
14+
`Focusable` 属性启用或禁用 `InputElement` 的焦点能力。无法获得焦点的元素仍然可以通过指针进行交互,因此应尽量确保提供具备功能性的键盘等效操作(如快捷键)。
15+
16+
## 显式聚焦
17+
18+
要显式地将焦点分配给任何 `InputElement`,可以在代码中调用其 `.Focus()` 方法。可选地,可以指定 `NavigationMethod``KeyModifiers` 以模拟特定的焦点导航流程。显式聚焦通常用于在加载数据输入表单时聚焦特定的 `InputElement`,或者在当前输入满足后程序化地移动到下一个 `InputControl`
19+
20+
| NavigationMethod | 触发描述 |
21+
|:-----------------|:---------------------------|
22+
| Tab | 按下 Tab 键 |
23+
| Pointer | 指针交互 |
24+
| Directional | 2D 方向性 (`XYFocus`) |
25+
| Unspecified | 默认 |
26+
27+
## 焦点事件
28+
29+
`InputElement` 暴露了 `GotFocus``LostFocus` 事件。`GotFocusEventArgs` 包含触发焦点导航的 `NavigationMethod``KeyModifiers`
30+
31+
## 焦点伪类
32+
33+
这些伪类在为 `Focusable``Control` 设置样式时非常有用。
34+
35+
| 伪类 | 描述 |
36+
|:---------------|----------------------------------------------------------------|
37+
| :focus | 控件具有焦点。 |
38+
| :focus-within | 控件具有焦点或包含具有焦点的子元素。 |
39+
| :focus-visible | 控件具有焦点并应显示视觉指示器。 |
40+
41+
:::tip
42+
`FocusAdorner` 属性用于在 `:focus-visible``Control` 周围显示默认的焦点视觉效果,通常是 `Border`。当使用 `:focus-visible` 显示自定义视觉指示器时,将 `FocusAdorner` 设置为 `null` 可避免显示重复的指示器。
43+
:::
44+
45+
## FocusManager
46+
47+
`FocusManager` 提供对焦点功能的全局访问,例如检索当前聚焦的元素或清除焦点。有关更多信息,请参阅 [FocusManager 文档](../services/focus-manager)
48+
49+
## Tab 焦点导航
50+
51+
当用户在键盘上按下 Tab 键时,会发生 Tab 焦点导航。将 `IsTabStop` 属性设置为 `true``InputElement` 将可用于 Tab 焦点导航。`TabIndex` 指定了优先级,数值较低的元素会先被导航到。当多个控件的 `TabIndex` 相等时,优先级基于视觉树遍历顺序。
52+
`KeyboardNavigation.TabNavigation` 附加属性可以为作为容器的任何 `InputElement` 设置 `KeyboardNavigationMode`,并修改其 Tab 导航特性。
53+
| KeyboardNavigationMode | 容器项遍历 |
54+
|:-----------------------|:----------------------------------------------------------|
55+
| Continue | 继续遍历项目并进入下一个容器 |
56+
| Cycle | 在自身项目中循环遍历 |
57+
| Contained | 停止在开始/结束项 |
58+
| Once | 容器和子元素仅作为一组获得焦点一次 |
59+
| None | 项目不会通过 Tab 导航获得焦点 |
60+
| Local | 仅考虑本地子树中的 `TabIndex` |
61+
62+
## 方向性焦点导航 <MinVersion version="11.1" />
63+
64+
通过 `XYFocus` 实现的焦点导航是一种 2D 方向性方案,允许从聚焦的控件向另一个控件进行空间导航,方向包括左、右、上、下。默认情况下,`XYFocus.NavigationModes` 被设置为允许 `Gamepad``Remote` 导航。
65+
66+
| KeyDeviceType | 设备 |
67+
|:--------------|:------------------------------------------|
68+
| Disabled | 任何按键设备的 XY 导航已禁用。 |
69+
| Keyboard | 可以使用键盘箭头键。 |
70+
| Gamepad | 可以使用游戏手柄的 DPad。 |
71+
| Remote | 可以使用遥控器。 |
72+
| Enabled | 所有设备都可以使用。 |
73+
74+
支持游戏手柄输入的设备包括可以原生发送这些输入的设备,如 Android 和 Tizen。然而,Avalonia 当前缺乏跨平台的游戏手柄 API,因此无法广泛地开箱即用地支持。
75+
76+
### 导航策略
77+
78+
当启用 2D 方向性导航时,将使用一种消歧策略来选择导航目标。
79+
| XYFocusNavigationStrategy | 导航目标 |
80+
|:----------------------------|:------------------------------------------------------------------------------|
81+
| Auto | 继承自祖先的策略。如果没有任何祖先指定,则使用投影策略。 |
82+
| Projection | 在导航方向上投影一条线时遇到的第一个元素。 |
83+
| NavigationDirectionDistance | 最接近导航线轴的元素。 |
84+
| RectilinearDistance | 基于最短曼哈顿距离的最近元素。 |
85+
86+
### 显式导航
87+
88+
`XYFocus` 允许每个控件在按下某个方向时指定显式的导航目标,通过 `XYFocus.Up``XYFocus.Down``XYFocus.Left``XYFocus.Right`。这优先于任何导航策略。
89+
90+
:::warning
91+
焦点参与尚未实现,因此将方向性焦点导航与自身处理方向输入的控件结合使用可能会有一些限制,尤其是在视觉效果方面。
92+
:::
93+
94+
### 示例
95+
96+
以下示例展示了如何在 `WrapPanel` 中使用方向性焦点导航。它显式地允许从第一个元素导航到最后一个元素,反之亦然。
97+
98+
`Slider` 提供了一个混合导航和控件交互的示例。在桌面平台上,当 `Slider` 获得焦点时按下 Enter 键将开始一个交互过程,用户将修改 `Slider.Value` 而不是导致导航。再次按下 Enter 键将结束交互并恢复方向性焦点导航。
99+
100+
```xml
101+
<Window
102+
XYFocus.NavigationModes="Enabled"
103+
XYFocus.UpNavigationStrategy="Projection"
104+
XYFocus.DownNavigationStrategy="Projection"
105+
XYFocus.LeftNavigationStrategy="Projection"
106+
XYFocus.RightNavigationStrategy="Projection">
107+
<Grid>
108+
<WrapPanel>
109+
<Button x:Name="first"
110+
Content="First"
111+
XYFocus.Left="{Binding #last}" />
112+
<Button Content="Second" />
113+
<Button Content="Third" />
114+
115+
<Slider Width="100" Maximum="100" />
116+
117+
<Button Content="Fourth" />
118+
<Button x:Name="last"
119+
Content="Last"
120+
XYFocus.Right="{Binding #first}" />
121+
</WrapPanel>
122+
</Grid>
123+
</Window>
124+
```
125+
126+
<img src={DirectionalNavigationScreenshot} alt="Directional Navigation Example"/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
---
2+
id: markupextensions
3+
title: Markup Extensions
4+
---
5+
6+
`Markup Extension` 允许在 XAML 中以方便、可重用的语法对目标属性的 setter 逻辑进行基于代码的自定义。大括号用于区分普通文本的使用。
7+
Avalonia 提供了以下内容:
8+
| MarkupExtension | 分配给属性 |
9+
|--------------------------------------------------------------------------------------------------|--------------------------------------------------------------------|
10+
| [StaticResource](/docs/guides/styles-and-resources/resources#static-resource) | 一个现有的键资源,并且不会在更改时更新 |
11+
| [DynamicResource](/docs/guides/styles-and-resources/resources#using-resources) | 延迟加载的键资源,会在更改时更新 |
12+
| Binding | 基于默认的绑定偏好:编译或反射 |
13+
| [CompiledBinding](/docs/basics/data/data-binding/compiled-bindings#compiledbinding-markup) | 基于编译的绑定 |
14+
| [ReflectionBinding](/docs/basics/data/data-binding/compiled-bindings#reflectionbinding-markup) | 基于反射的绑定 |
15+
| [TemplateBinding](/docs/guides/custom-controls/how-to-create-templated-controls#data-binding) | 基于简化的绑定,仅在 `ControlTemplate` 内使用 |
16+
| [OnPlatform](/docs/guides/platforms/platform-specific-code/xaml#onplatform-markup-extension) | 当处于指定平台时有条件地使用 |
17+
| [OnFormFactor](/docs/guides/platforms/platform-specific-code/xaml#onformfactor-markup-extension) | 当处于指定因素时有条件地使用 |
18+
19+
## 编译器内在函数
20+
21+
这些技术上不属于 `MarkupExtension`,而是 XAML 编译器的一部分,但 和XAML 语法相同。
22+
23+
| 内在函数 | 分配给属性 |
24+
|-----------|-----------------------|
25+
| x:True | `true` 字面量 |
26+
| x:False | `false` 字面量 |
27+
| x:Null | `null` 字面量 |
28+
| x:Static | 静态成员值 |
29+
| x:Type | `System.Type` 字面量 |
30+
31+
`x:True``x:False` 字面量在目标绑定属性为 `object` 且需要提供布尔值的情况下有用。在这些缺少类型信息的场景中,提供 "True" 仍然是一个字符串。
32+
33+
```xml
34+
<Button Command="{Binding SetStateCommand}" CommandParameter="{x:True}" />
35+
```
36+
37+
## 创建 MarkupExtensions
38+
39+
派生自 `MarkupExtension` 或添加以下通过鸭子类型支持的签名之一:
40+
41+
```csharp
42+
T ProvideValue();
43+
T ProvideValue(IServiceProvider provider);
44+
object ProvideValue();
45+
object ProvideValue(IServiceProvider provider);
46+
```
47+
48+
当使用强类型而不是 `object` 时,如果在 XAML 中构造参数、属性或 `ProvideValue` 中的返回值不匹配,将会收到编译时错误。当返回 `object` 时,实际返回的类型必须与目标属性的类型匹配,否则运行时会抛出 `InvalidCastException`
49+
50+
### 接收字面量参数
51+
52+
当需要参数时,使用构造函数按顺序接收每个参数。
53+
54+
对于可选或无序参数,使用属性代替。允许混合使用多个构造函数,包括无参数构造函数。
55+
56+
```csharp
57+
public class MultiplyLiteral
58+
{
59+
private readonly double _first;
60+
private readonly double _second;
61+
62+
public double? Third { get; set; }
63+
public MultiplyLiteral(double first, double second)
64+
{
65+
_first = first;
66+
_second = second;
67+
}
68+
public double ProvideValue(IServiceProvider provider)
69+
{
70+
return First * Second * Third ?? 1;
71+
}
72+
}
73+
```
74+
```xml
75+
<TextBlock Text="This has FontSize=40" FontSize="{namespace:MultiplyLiteral 10, 8, Third=0.5}" />
76+
```
77+
78+
### 从绑定接收参数
79+
80+
常见的场景是希望转换来自绑定的数据并更新目标属性。当所有参数都来自绑定时,通过创建一个带有 `IMultiValueConverter``MultiBinding` 来实现这一点相对简单。在下面的示例中,`MultiplyBinding` 需要两个绑定参数。如果需要混合字面量和绑定参数,创建一个 `IMultiValueConverter` 可以允许传递字面量作为构造函数或 `init` 参数。`BindingBase` 允许使用 `CompiledBinding``ReflectionBinding`,但不允许使用字面量。
81+
82+
```csharp
83+
public class MultiplyBinding
84+
{
85+
private readonly BindingBase _first;
86+
private readonly BindingBase _second;
87+
public MultiplyBinding(BindingBase first, BindingBase second)
88+
{
89+
_first = first;
90+
_second = second;
91+
}
92+
public object ProvideValue()
93+
{
94+
var mb = new MultiBinding()
95+
{
96+
Bindings = new[] { _first, _second },
97+
Converter = new FuncMultiValueConverter<double, double>(doubles => doubles.Aggregate(1d, (x, y) => x * y))
98+
};
99+
return mb;
100+
}
101+
}
102+
```
103+
104+
```xml
105+
<TextBlock FontSize="{local:MultiplyBinding {Binding Multiplier}, {Binding Multiplicand}}"
106+
Text="MarkupExtension with Bindings!" />
107+
```
108+
109+
:::info
110+
另一种方法是返回 `IObservable<T>.ToBinding()`
111+
:::
112+
113+
### 返回参数
114+
115+
为了使 `MarkupExtension` 兼容多种目标属性类型,返回 `object` 并分别处理每种支持的类型。
116+
117+
```csharp
118+
public object ProvideValue(IServiceProvider provider)
119+
{
120+
var target = (IProvideValueTarget)provider.GetService(typeof(IProvideValueTarget))!;
121+
var targetProperty = target.TargetProperty as AvaloniaProperty;
122+
var targetType = targetProperty?.PropertyType;
123+
double result = First * Second * (Third ?? 1);
124+
if (targetType == typeof(double))
125+
return result;
126+
else if (targetType == typeof(float))
127+
return (float)result;
128+
else if (targetType == typeof(int))
129+
return (int)result;
130+
else
131+
throw new NotSupportedException();
132+
}
133+
```
134+
135+
构造函数也可以使用 `object` 方法接收参数类型,但编译时错误同样会变成运行时异常。
136+
137+
### MarkupExtension 属性注解
138+
139+
* `[ConstructorArgument]` - 关联属性可以通过构造函数参数初始化,并且如果使用了构造函数,则在 XAML 序列化时应忽略该属性。
140+
* `[MarkupExtensionOption]`, `[MarkupExtensionDefaultOption]` - 与 `ShouldProvideOption` 一起使用,查看 `OnPlatform``OnFormFactor` 的源代码以获取示例。

0 commit comments

Comments
 (0)