Skip to content

Commit

Permalink
Merge branch 'main' into deploy
Browse files Browse the repository at this point in the history
  • Loading branch information
zdpcdt committed Aug 11, 2023
2 parents eb4928f + bd8b55f commit 918f927
Show file tree
Hide file tree
Showing 13 changed files with 189 additions and 223 deletions.
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
---
id: binding-classes
title: How To Bind Style Classes
title: 如何绑定样式类
---


# How To Bind Style Classes
# 如何绑定样式类

This guide will show you how to apply style classes to a control depending on the Boolean value of a data binding. 
本指南将向您展示如何根据数据绑定的布尔值为控件应用样式类。

To do this, you will need some classes defined in a `<Styles>` collection that target the control class you are using.
要做到这一点,您需要在一个 `<Styles>` 集合中定义一些针对您正在使用的控件类的类。

You can then conditionally apply the classes to a control using special classes syntax and a data binding. The syntax is like this:
然后,您可以使用特殊的类语法和数据绑定有条件地将类应用于控件。语法如下:

```
<SomeControl Classes.class1="Binding IsClass1Active}">
```

## Example
## 示例

In this example, two styles with class selectors have been defined. These give a text block either a red or a green background. The style class binding assigns `class1` when the `IsClass1` property of an item is true. Using the negation operator, `class2` is assigned when the `IsClass1` property is false.
在这个示例中,已经定义了两个带有类选择器的样式。这些样式为文本块提供了红色或绿色的背景。当项目的 `IsClass1` 属性为真时,样式类绑定将分配 `class1`。使用否定运算符,当 `IsClass1` 属性为假时,将分配 `class2`

```xml title='XAML'
<StackPanel Margin="20">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,64 +1,64 @@
---
id: binding-from-code
title: How To Bind from Code
title: 如何从代码中绑定
---


# How To Bind from Code
# 如何从代码中绑定

Binding from code in Avalonia works somewhat differently to WPF/UWP. At the low level, Avalonia's binding system is based on Reactive Extensions' `IObservable` which is then built upon by XAML bindings (which can also be instantiated in code).
在Avalonia中,从代码中绑定与WPF/UWP中的方式有些不同。在底层,Avalonia的绑定系统基于Reactive Extensions的 `IObservable`,然后由XAML绑定进行构建(这些绑定也可以在代码中实例化)。

## Subscribing to Changes to a Property
## 订阅属性的更改

You can subscribe to changes on a property by calling the `GetObservable` method. This returns an `IObservable<T>` which can be used to listen for changes to the property:
您可以通过调用 `GetObservable` 方法来订阅属性的更改。这将返回一个 `IObservable<T>`,可用于监听属性的更改:

```csharp
var textBlock = new TextBlock();
var text = textBlock.GetObservable(TextBlock.TextProperty);
```

Each property that can be subscribed to has a static readonly field called `[PropertyName]Property` which is passed to `GetObservable` in order to subscribe to the property's changes.
每个可订阅的属性都有一个静态只读字段,称为 `[PropertyName]Property`,该字段在 `GetObservable` 中传递以订阅属性的更改。

`IObservable` (part of Reactive Extensions, or rx for short) is out of scope for this guide, but here's an example which uses the returned observable to print a message with the changing property values to the console:
`IObservable`(是Reactive Extensions的一部分,简称为rx)超出了本指南的范围,但以下是一个示例,该示例使用返回的可观察对象将更改的属性值打印到控制台:

```csharp
var textBlock = new TextBlock();
var text = textBlock.GetObservable(TextBlock.TextProperty);
text.Subscribe(value => Console.WriteLine(value + " Changed"));
```

When the returned observable is subscribed, it will return the current value of the property immediately and then push a new value each time the property changes. If you don't want the current value, you can use the rx `Skip` operator:
当订阅返回的可观察对象时,它将立即返回属性的当前值,然后在每次属性更改时推送一个新值。如果您不想要当前值,可以使用 rx `Skip` 运算符:

```csharp
var text = textBlock.GetObservable(TextBlock.TextProperty).Skip(1);
```

## Binding to an observable
## 绑定到可观察对象

You can bind a property to an observable using the `AvaloniaObject.Bind` method:
您可以使用 `AvaloniaObject.Bind` 方法将属性绑定到可观察对象:

```csharp
// We use an Rx Subject here so we can push new values using OnNext
// 在这里我们使用Rx Subject,以便我们可以使用OnNext推送新值
var source = new Subject<string>();
var textBlock = new TextBlock();

// Bind TextBlock.Text to source
// 将TextBlock.Text绑定到source
var subscription = textBlock.Bind(TextBlock.TextProperty, source);

// Set textBlock.Text to "hello"
// 将textBlock.Text设置为"hello"
source.OnNext("hello");
// Set textBlock.Text to "world!"
// 将textBlock.Text设置为"world!"
source.OnNext("world!");

// Terminate the binding
// 终止绑定
subscription.Dispose();
```

Notice that the `Bind` method returns an `IDisposable` which can be used to terminate the binding. If you never call this, then then binding will automatically terminate when the observable finishes via `OnCompleted` or `OnError`.
请注意,`Bind` 方法返回一个 `IDisposable`,可用于终止绑定。如果您从不调用此方法,那么当可观察对象通过 `OnCompleted` `OnError` 结束时,绑定将自动终止。

## Setting a binding in an object initializer
## 在对象初始化器中设置绑定

It is often useful to set up bindings in object initializers. You can do this using the indexer:
在对象初始化器中设置绑定通常很有用。您可以使用索引器来实现此目的:

```csharp
var source = new Subject<string>();
Expand All @@ -70,7 +70,7 @@ var textBlock = new TextBlock
};
```

Using this method you can also easily bind a property on one control to a property on another:
使用此方法,您还可以轻松地将一个控件的属性绑定到另一个控件的属性:

```csharp
var textBlock1 = new TextBlock();
Expand All @@ -82,17 +82,17 @@ var textBlock2 = new TextBlock
};
```

Of course the indexer can be used outside object initializers too:
当然,索引器也可以在对象初始化器之外使用:

```csharp
textBlock2[!TextBlock.TextProperty] = textBlock1[!TextBlock.TextProperty];
```

The only downside of this syntax is that no `IDisposable` is returned. If you need to manually terminate the binding then you should use the `Bind` method.
这种语法的唯一缺点是不会返回 `IDisposable`。如果您需要手动终止绑定,则应使用 `Bind` 方法。

## Transforming binding values
## 转换绑定值

Because we're working with observables, we can easily transform the values we're binding!
因为我们使用的是可观察对象,所以可以很容易地转换我们绑定的值!

```csharp
var source = new Subject<string>();
Expand All @@ -104,9 +104,9 @@ var textBlock = new TextBlock
};
```

## Using XAML bindings from code
## 从代码中使用 XAML 绑定

Sometimes when you want the additional features that XAML bindings provide, it's easier to use XAML bindings from code. For example, using only observables you could bind to a property on `DataContext` like this:
有时,当您想要使用XAML绑定提供的附加功能时,从代码中使用 XAML 绑定会更加容易。例如,仅使用可观察对象,您可以像这样绑定到 `DataContext` 上的属性:

```csharp
var textBlock = new TextBlock();
Expand All @@ -116,7 +116,7 @@ var viewModelProperty = textBlock.GetObservable(TextBlock.DataContext)
textBlock.Bind(TextBlock.TextProperty, viewModelProperty);
```

However, it might be preferable to use a XAML binding in this case:
然而,在这种情况下,使用 XAML 绑定可能更可取:

```csharp
var textBlock = new TextBlock
Expand All @@ -125,7 +125,7 @@ var textBlock = new TextBlock
};
```

Or, if you need an `IDisposable` to terminate the binding:
或者,如果您需要一个 `IDisposable` 来终止绑定:

```csharp
var textBlock = new TextBlock();
Expand All @@ -134,17 +134,17 @@ var subscription = textBlock.Bind(TextBlock.TextProperty, new Binding("Name"));
subscription.Dispose();
```

## Subscribing to a Property on Any Object
## 订阅任何对象的属性

The `GetObservable` method returns an observable that tracks changes to a property on a single instance. However, if you're writing a control you may want to implement an `OnPropertyChanged` method which isn't tied to an instance of an object.
`GetObservable` 方法返回一个可观察对象,用于跟踪单个实例上属性的更改。但是,如果您正在编写一个控件,可能希望实现一个与对象实例无关的 `OnPropertyChanged` 方法。

To do this you can subscribe to [`AvaloniaProperty.Changed`](http://reference.avaloniaui.net/api/Avalonia/AvaloniaProperty/65237C52) which is an observable which fires _every time the property is changed on any instance_.
要做到这一点,您可以订阅 [`AvaloniaProperty.Changed`](http://reference.avaloniaui.net/api/Avalonia/AvaloniaProperty/65237C52),这是一个可观察对象,_每次在任何实例上更改属性时都会触发该对象_

> In WPF this is done by passing a static `PropertyChangedCallback` to the `DependencyProperty` registration method, but this only allows the control author to register a property changed callback.
> WPF 中,通过将静态的 `PropertyChangedCallback` 传递给 `DependencyProperty` 注册方法来完成此操作,但这只允许控件作者注册属性更改回调。
In addition there is an `AddClassHandler` extension method which can automatically route the event to a method on your control.
此外,还有一个 `AddClassHandler` 扩展方法,可以自动将事件路由到控件上的方法。

For example if you want to listen to changes to your control's `Foo` property you'd do it like this:
例如,如果您想要监听对控件的 `Foo` 属性的更改,可以像这样做:

```csharp
static MyControl()
Expand All @@ -154,13 +154,13 @@ static MyControl()

private void FooChanged(AvaloniaPropertyChangedEventArgs e)
{
// The 'e' parameter describes what's changed.
// 'e' 参数描述了发生的更改。
}
```

## Binding to `INotifyPropertyChanged` objects
## 绑定到实现了 `INotifyPropertyChanged` 的对象

Binding to objects that implements `INotifyPropertyChanged` is also available.
也可以绑定到实现了 `INotifyPropertyChanged` 的对象。

```csharp
var textBlock = new TextBlock();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,48 +1,48 @@
---
id: binding-to-controls
title: How To Bind to a Control
title: 如何绑定到控件
---


# How To Bind to a Control
# 如何绑定到控件

With _Avalonia UI_, as well as binding to a data context you can also bind one control directly to another.
_Avalonia UI_ 中,除了绑定到数据上下文(DataContext)外,您还可以直接将一个控件绑定到另一个控件。

:::info
Note that this technique does not use a data context at all. When you do this, you are binding directly to another control itself.&#x20;
请注意,这种技术完全不使用数据上下文。在执行此操作时,您是直接将一个控件绑定到另一个控件本身。
:::

## Binding to a Named Control
## 绑定到命名控件

If you want to bind to a property on another named control, you can use the control name prefixed by a `#` character.
如果要绑定到另一个命名控件上的属性,可以使用以 `#` 字符为前缀的控件名称。

```markup
<TextBox Name="other">
<!-- Binds to the Text property of the "other" control -->
<!-- 绑定到命名为 other 控件的 Text 属性 -->
<TextBlock Text="{Binding #other.Text}"/>
```

This is the equivalent to the long-form binding that will be familiar to WPF and UWP users:
这相当于 WPF UWP 开发者熟悉的长格式绑定:

```markup
<TextBox Name="other">
<TextBlock Text="{Binding Text, ElementName=other}"/>
```

_Avalonia UI_ supports both syntaxes.
_Avalonia UI_ 支持这两种语法。

## Binding to an Ancestor
## 绑定到祖先控件

You can bind to the (logical control tree) parent of the target using the `$parent` syntax:
您可以使用 `$parent` 语法绑定到目标的(逻辑控件树)父级:

```markup
<Border Tag="Hello World!">
<TextBlock Text="{Binding $parent.Tag}"/>
</Border>
```

Or to any level of ancestor by using an index with the `$parent` syntax:
或者使用带有 `$parent` 语法的索引绑定到任何级别的祖先:

```markup
<Border Tag="Hello World!">
Expand All @@ -52,9 +52,9 @@ Or to any level of ancestor by using an index with the `$parent` syntax:
</Border>
```

The index is zero based so `$parent[0]` is equivalent to `$parent`.
索引从0开始,因此 `$parent[0]` 等同于 `$parent`

You can also bind to the closest ancestor of a given type, like this:
您还可以绑定到指定类型的最近祖先,如下所示:

```markup
<Border Tag="Hello World!">
Expand All @@ -64,7 +64,7 @@ You can also bind to the closest ancestor of a given type, like this:
</Border>
```

Finally, you can combine the index and the type:
最后,您可以结合索引和类型:

```markup
<Border Tag="Hello World!">
Expand All @@ -76,7 +76,7 @@ Finally, you can combine the index and the type:
</Border>
```

If you need to include a XAML namespace in the ancestor type, you separate the namespace and class using a colon, like this:
如果需要在祖先类型中包含 XAML 命名空间,则使用冒号分隔命名空间和类名,如下所示:

```markup
<local:MyControl Tag="Hello World!">
Expand All @@ -87,5 +87,5 @@ If you need to include a XAML namespace in the ancestor type, you separate the n
```

:::warning
_Avalonia UI_ also supports WPF/UWP's `RelativeSource` syntax which does something similar, but is _not_ the same. `RelativeSource` works on the _visual_ tree whereas the syntax given here works on the _logical_ tree.
_Avalonia UI_ 还支持 WPF/UWP`RelativeSource` 语法,类似但并不相同。`RelativeSource` _视觉_ 树上起作用,而此处给出的语法在 _逻辑_ 树上起作用。
:::
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
---
id: how-to-bind-can-execute
title: How to Bind Can Execute
title: 如何绑定 Can Execute
---


# How to Bind Can Execute
# 如何绑定 Can Execute

Whether a control, that can initiate an action in response to user interaction, is in its enabled state, is an important principle of the 'revealed functionality' part of user experience design (UX). User confidence is reinforced by disabling commands that cannot run. For example where a button or menu item cannot run due to the current state of an application, they should be presented as inactive.
控件是否处于启用状态,可以响应用户交互并触发操作,是用户体验设计(UX)中“功能可见性”部分的重要原则。通过禁用无法运行的命令,可以增强用户的信心。例如,如果按钮或菜单项由于应用程序的当前状态而无法运行,则应呈现为不活动状态。

This example assumes that you are using the MVVM implementation pattern with the _ReactiveUI_ framework. This (recommended) approach gives a very clear separation between the view and the view model.
本示例假设您正在使用带有 _ReactiveUI_ 框架的 MVVM 实现模式。这种(推荐的)方法在视图和视图模型之间提供了非常清晰的分离。

In this example, the button can only be clicked when the message is not empty. As soon as the output is shown; the message is reset to the empty string - which in turn will disable the button again.
在此示例中,只有在消息不为空时,才能单击按钮。一旦输出显示出来,消息就会重置为空字符串,从而再次禁用按钮。

```xml title='XAML'
<StackPanel Margin="20">
Expand Down Expand Up @@ -74,16 +74,16 @@ namespace AvaloniaGuides.ViewModels
}
```

In the constructor of the view model, the reactive command is created with two parameters. The first is the private method that performs the action. The second is an observable which is created by the `WhenAnyValue` method of the `ReactiveObject` that underlies the view model (from the `ViewModelBase` class).&#x20;
在视图模型的构造函数中,使用两个参数创建了响应式命令。第一个参数是执行操作的私有方法。第二个参数是由视图模型(来自 `ViewModelBase` 类)的 `ReactiveObject` `WhenAnyValue` 方法创建的可观察对象。

:::info
The `ViewModelBase` class is added to your project when you use the 'Avalonia MVVM Application' solution template.
在使用 "Avalonia MVVM Application" 解决方案模板时,将会向您的项目中添加 `ViewModelBase` 类。
:::

Here the `WhenAnyValue` method takes two arguments, the first collects a value for the parameter of the validation function, and the second is the validation function that returns a Boolean result.&#x20;
在这里,`WhenAnyValue` 方法接受两个参数,第一个参数收集验证函数参数的值,第二个参数是返回布尔结果的验证函数。

:::info
The `WhenAnyValue` method actually has overloads that can take up to 10 different value getters (for the validation function parameters), plus the validation function itself. &#x20;
实际上,`WhenAnyValue` 方法有多个重载,最多可以接受 10 个不同的值获取器(用于验证函数参数),以及验证函数本身。
:::

<img src="/img/gitbook-import/assets/command4.gif" alt=""/>
Loading

0 comments on commit 918f927

Please sign in to comment.