diff --git a/README/重要说明.md b/README/重要说明.md index a31bd52..e73cef4 100644 --- a/README/重要说明.md +++ b/README/重要说明.md @@ -551,4 +551,301 @@ private void Window_Closed(object sender, EventArgs e) > - **`OnLoaded`**:窗口完全加载并显示后调用。 > - **`Activated`**:窗口获得焦点并被激活时触发。 > - **`OnClosing`**:窗口即将关闭时调用。 -> - **`OnClosed`**:窗口完全关闭后调用。 \ No newline at end of file +> - **`OnClosed`**:窗口完全关闭后调用。 + +## WPF绑定模式 + +在 WPF(Windows Presentation Foundation)中,**数据绑定**(Data Binding)是一项核心功能,它允许将用户界面(UI)控件与数据源之间建立连接,从而使得 UI 和数据之间能够自动同步。WPF 提供了多种**绑定模式**(Binding Modes),每种模式都有其特定的行为和用途,用于处理数据从视图到视图模型(或模型)的更新、同步等。 + +### WPF 中的绑定模式 + +WPF 支持四种主要的绑定模式(Binding Modes): + +1. **OneWay(单向绑定)** +2. **TwoWay(双向绑定)** +3. **OneWayToSource(单向绑定到源)** +4. **OneTime(一次性绑定)** + +#### 1. **OneWay(单向绑定)** + +**定义**:单向绑定模式将数据源的变化反映到 UI 元素中,即数据从数据源到视图(UI)。数据从源控件(如模型、视图模型)流向目标控件(如文本框、标签等)。 + +**特点**: + +- 数据流动方向是从数据源到目标控件。 +- UI 元素的变化不会影响数据源。 +- 常用于显示数据,不需要用户交互修改数据。 + +**示例**:绑定一个 `Label` 的 `Content` 属性到一个模型的属性。 + +```xml + +public class Person +{ + public string Name { get; set; } +} + +// 在视图模型中绑定: +public class MainViewModel +{ + public Person Person { get; set; } = new Person { Name = "John Doe" }; +} +``` + +#### 2. **TwoWay(双向绑定)** + +**定义**:双向绑定允许数据在两个方向流动,既可以从源到目标,也可以从目标到源。当用户更改 UI 元素的值时,数据源会自动更新;同样,当数据源发生变化时,UI 元素会同步更新。 + +**特点**: + +- 数据流动是双向的(源 -> 目标 和 目标 -> 源)。 +- 常用于用户输入的场景,如文本框输入、下拉框选择等。 +- 适用于需要用户交互且 UI 需要实时反映的数据。 + +**示例**:绑定一个 `TextBox` 的 `Text` 属性到视图模型中的属性。 + +```xml + +public class Person +{ + public string Name { get; set; } +} + +// 在视图模型中绑定: +public class MainViewModel +{ + public Person Person { get; set; } = new Person { Name = "John Doe" }; +} +``` + +如果用户在 `TextBox` 中输入内容,`Person.Name` 会自动更新为输入的值。 + +#### 3. **OneWayToSource(单向绑定到源)** + +**定义**:这种绑定模式与 `OneWay` 类似,但数据流动的方向相反。它将 UI 元素的变化反映到数据源,即从目标控件(如文本框、按钮等)到数据源。 + +**特点**: + +- 数据流动方向是从目标到数据源。 +- 适用于一些需要监听 UI 元素变化并更新数据源的场景,但不要求数据源的变化影响到 UI 元素。 +- 一般用于用户输入的情况,数据源的更改不需要直接反映到 UI 上。 + +**示例**:将 `TextBox` 的 `Text` 属性绑定到数据源,并将用户输入的值更新到数据源中。 + +```xml + +public class Person +{ + public string Name { get; set; } +} + +// 在视图模型中绑定: +public class MainViewModel +{ + public Person Person { get; set; } = new Person { Name = "John Doe" }; +} +``` + +当用户在 `TextBox` 中输入内容时,`Person.Name` 会自动更新,但不会反过来更新 `TextBox`。 + +#### 4. **OneTime(一次性绑定)** + +**定义**:一次性绑定模式将数据源的值传递给目标控件,但不会再进行同步更新。数据只在初始时绑定一次,之后不会跟随数据源的变化而更新。 + +**特点**: + +- 数据仅在第一次绑定时传递到目标控件。 +- 适用于不需要随数据源变化自动更新 UI 的场景。 +- 适用于静态数据,如初始化时显示的值。 + +**示例**:在应用启动时绑定初始数据。 + +```xml + +public class Person +{ + public string Name { get; set; } +} + +// 在视图模型中绑定: +public class MainViewModel +{ + public Person Person { get; set; } = new Person { Name = "John Doe" }; +} +``` + +`TextBlock` 的 `Text` 属性会在应用启动时绑定一次,但在之后的任何数据变化都不会反映到 UI 上。 + +### 选择合适的绑定模式 + +选择绑定模式时需要根据实际需求来决定。以下是不同情况适用的模式: + +1. **`OneWay`**: + - 用于显示数据,UI 不需要编辑或修改数据。 + - 适用于只读的文本展示等场景。 +2. **`TwoWay`**: + - 用于需要用户输入并与数据源实时同步的场景。 + - 适用于输入框、下拉框等用户可编辑控件。 +3. **`OneWayToSource`**: + - 用于需要监听 UI 元素的变化并更新数据源的场景,且不需要将数据源的变化反映回 UI。 + - 适用于需要提交用户输入但不需要实时更新 UI 的场景。 +4. **`OneTime`**: + - 用于初始化数据,仅绑定一次,之后不再更新。 + - 适用于静态数据或加载一次后不再变化的场景。 + +### 绑定模式的代码示例 + +以下是完整的 `TwoWay` 绑定的代码示例: + +```xml + + + + + +public class MainWindowViewModel +{ + public string Name { get; set; } = "John Doe"; +} + +public partial class MainWindow : Window +{ + public MainWindow() + { + InitializeComponent(); + DataContext = new MainWindowViewModel(); + } +} +``` + +在这个示例中,`TextBox` 的 `Text` 属性绑定到了视图模型中的 `Name` 属性,且使用 `TwoWay` 模式,意味着如果用户修改 `TextBox` 中的内容,`Name` 属性会实时更新,反之,`Name` 的变化会反映在 `TextBox` 中。 + +在 WPF 中,**多绑定**(Multiple Bindings)是指将一个目标控件的属性绑定到多个数据源上,或使用多个绑定来决定控件的显示内容。通常情况下,我们可以使用 `MultiBinding` 和 `IMultiValueConverter` 来实现多绑定。 + +### **基础多绑定示例** + +`MultiBinding` 允许你将多个数据源绑定到一个目标控件上,并通过一个 `IMultiValueConverter` 将多个数据源的值转换为一个值,从而决定目标控件的最终显示。 + +假设我们有两个文本框,用户分别输入名字和姓氏,我们想在一个 `TextBlock` 中显示完整的姓名。我们可以使用 `MultiBinding` 来实现。 + +#### XAML 示例: + +```xml + + + + + + + + + + + + + + + + + + + + + + +``` + +> 1. `MultiBinding` 允许你将多个绑定连接到同一个目标控件(这里是 `TextBlock.Text`)。 +> 2. 绑定的源控件是 `FirstNameTextBox` 和 `LastNameTextBox`。 +> 3. 使用 `IMultiValueConverter`(在这个例子中是 `FullNameConverter`)将多个绑定的值(名字和姓氏)转换为一个最终值并显示在 `TextBlock` 中。 + +### `MultiBinding` 进阶 + +`MultiBinding` 可以用于处理更复杂的场景,比如通过多个条件来决定控件的属性值。例如,依据多个条件显示不同的文本或颜色。 + +#### XAML 示例: + +```xml + + + + + + + + + + + + + + + + + + + + Text Block Color Based on Conditions + + + +``` + +#### `TextColorConverter` 实现: + +```csharp +using System; +using System.Globalization; +using System.Windows.Data; +using System.Windows.Media; + +namespace WpfApp +{ + public class TextColorConverter : IMultiValueConverter + { + public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) + { + bool isActive = (bool)(values[0] ?? false); + bool hasPermission = (bool)(values[1] ?? false); + + if (isActive && hasPermission) + { + return new SolidColorBrush(Colors.Green); // 如果两个条件都满足,显示绿色 + } + return new SolidColorBrush(Colors.Red); // 否则显示红色 + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + { + return null; // 不需要双向绑定 + } + } +} +``` + +> - 在这个例子中,`TextBlock.Foreground` 属性的颜色依赖于两个复选框的状态(`IsActiveCheckBox` 和 `HasPermissionCheckBox`)。 +> +> - ``` +> TextColorConverter +> ``` +> +> 判断两个条件: +> +> - 如果两个复选框都被选中,`TextBlock` 的颜色是绿色。 +> - 否则,颜色为红色。 +> +> 1. **绑定多个属性**:通过 `MultiBinding` 可以同时绑定多个数据源到一个目标控件的属性。在数据源变化时,`IMultiValueConverter` 将负责处理多个源的逻辑,返回最终的结果。 +> 2. **双向绑定**:虽然 `MultiBinding` 主要用于单向绑定(UI -> 数据源),如果需要双向绑定,可以通过设置 `Mode=TwoWay` 来实现。但一般来说,`MultiBinding` 多用于显示和数据转换,而不是双向交互。 +> 3. **性能**:在进行多绑定时,尤其是复杂的转换时,需要注意性能影响。如果绑定源的数量或更新频率较高,可能会影响应用的性能。 + diff --git a/WPF-重要示例.sln b/WPF-重要示例.sln index bb4ace1..e24995c 100644 --- a/WPF-重要示例.sln +++ b/WPF-重要示例.sln @@ -16,6 +16,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_7鼠标状态移动监视" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_8鼠标拖拽", "_8鼠标拖拽\_8鼠标拖拽.csproj", "{2B87A81A-A1B0-4243-92BD-1281097B79E2}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_9WPF绑定元素和绑定模式", "_9WPF绑定元素和绑定模式\_9WPF绑定元素和绑定模式.csproj", "{20E3BF0D-57DC-4BA5-8FB2-A06DC15008AF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -54,5 +56,9 @@ Global {2B87A81A-A1B0-4243-92BD-1281097B79E2}.Debug|Any CPU.Build.0 = Debug|Any CPU {2B87A81A-A1B0-4243-92BD-1281097B79E2}.Release|Any CPU.ActiveCfg = Release|Any CPU {2B87A81A-A1B0-4243-92BD-1281097B79E2}.Release|Any CPU.Build.0 = Release|Any CPU + {20E3BF0D-57DC-4BA5-8FB2-A06DC15008AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {20E3BF0D-57DC-4BA5-8FB2-A06DC15008AF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {20E3BF0D-57DC-4BA5-8FB2-A06DC15008AF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {20E3BF0D-57DC-4BA5-8FB2-A06DC15008AF}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/_9WPF绑定元素和绑定模式/App.xaml b/_9WPF绑定元素和绑定模式/App.xaml new file mode 100644 index 0000000..0d676f6 --- /dev/null +++ b/_9WPF绑定元素和绑定模式/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/_9WPF绑定元素和绑定模式/App.xaml.cs b/_9WPF绑定元素和绑定模式/App.xaml.cs new file mode 100644 index 0000000..5601d2f --- /dev/null +++ b/_9WPF绑定元素和绑定模式/App.xaml.cs @@ -0,0 +1,12 @@ +using System.Configuration; +using System.Data; +using System.Windows; + +namespace _WPF绑定元素和绑定模式; + +/// +/// Interaction logic for App.xaml +/// +public partial class App : Application +{ +} \ No newline at end of file diff --git a/_9WPF绑定元素和绑定模式/AssemblyInfo.cs b/_9WPF绑定元素和绑定模式/AssemblyInfo.cs new file mode 100644 index 0000000..4a05c7d --- /dev/null +++ b/_9WPF绑定元素和绑定模式/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] \ No newline at end of file diff --git a/_9WPF绑定元素和绑定模式/MainWindow.xaml b/_9WPF绑定元素和绑定模式/MainWindow.xaml new file mode 100644 index 0000000..450a630 --- /dev/null +++ b/_9WPF绑定元素和绑定模式/MainWindow.xaml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_9WPF绑定元素和绑定模式/MainWindow.xaml.cs b/_9WPF绑定元素和绑定模式/MainWindow.xaml.cs new file mode 100644 index 0000000..8590f33 --- /dev/null +++ b/_9WPF绑定元素和绑定模式/MainWindow.xaml.cs @@ -0,0 +1,45 @@ +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; + +namespace _WPF绑定元素和绑定模式; + +/// +/// Interaction logic for MainWindow.xaml +/// +public partial class MainWindow : Window +{ + public MainWindow() + { + InitializeComponent(); + Console.WriteLine("使用代码模式的绑定"); + + var binding = new Binding + { + Source = SliderFontSize, + Path = new PropertyPath("Value"), + Mode = BindingMode.TwoWay + }; + TextBlockShow.SetBinding(TextBlock.FontSizeProperty, binding); + } + + private void SetLarge_OnClick(object sender, RoutedEventArgs e) + { + SliderFontSize.Value = 100; + } + + private void SetNormal_OnClick(object sender, RoutedEventArgs e) + { + SliderFontSize.Value = 40; + } + + private void SetSmall_OnClick(object sender, RoutedEventArgs e) + { + SliderFontSize.Value = 10; + } + + private void ClearBinding_OnClick(object sender, RoutedEventArgs e) + { + BindingOperations.ClearAllBindings(TextBlockShow); + } +} \ No newline at end of file diff --git a/_9WPF绑定元素和绑定模式/_9WPF绑定元素和绑定模式.csproj b/_9WPF绑定元素和绑定模式/_9WPF绑定元素和绑定模式.csproj new file mode 100644 index 0000000..fae30e8 --- /dev/null +++ b/_9WPF绑定元素和绑定模式/_9WPF绑定元素和绑定模式.csproj @@ -0,0 +1,18 @@ + + + + WinExe + net8.0-windows + enable + enable + true + _WPF绑定元素和绑定模式 + + + + + Always + + + + diff --git a/_9WPF绑定元素和绑定模式/public/logo.png b/_9WPF绑定元素和绑定模式/public/logo.png new file mode 100644 index 0000000..5dedbe2 Binary files /dev/null and b/_9WPF绑定元素和绑定模式/public/logo.png differ