{"id":16246286,"url":"https://github.com/dingpingzhang/wpfextensions","last_synced_at":"2025-04-04T15:07:59.356Z","repository":{"id":40633360,"uuid":"166526898","full_name":"DingpingZhang/WpfExtensions","owner":"DingpingZhang","description":"Some syntactic sugar for Wpf development.","archived":false,"fork":false,"pushed_at":"2023-09-16T02:14:33.000Z","size":1307,"stargazers_count":274,"open_issues_count":1,"forks_count":27,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-28T14:06:56.892Z","etag":null,"topics":["binding","computed-property","markup-extension","mvvm","reactive","reactivity","wpf","xaml"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DingpingZhang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-01-19T08:58:20.000Z","updated_at":"2025-03-27T23:37:18.000Z","dependencies_parsed_at":"2024-06-21T13:07:41.197Z","dependency_job_id":"7c7e005e-3b37-4a99-b1aa-7e1c905e30f3","html_url":"https://github.com/DingpingZhang/WpfExtensions","commit_stats":null,"previous_names":["dingpingzhang/system.windows.extensions"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DingpingZhang%2FWpfExtensions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DingpingZhang%2FWpfExtensions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DingpingZhang%2FWpfExtensions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DingpingZhang%2FWpfExtensions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DingpingZhang","download_url":"https://codeload.github.com/DingpingZhang/WpfExtensions/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247198458,"owners_count":20900080,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["binding","computed-property","markup-extension","mvvm","reactive","reactivity","wpf","xaml"],"created_at":"2024-10-10T14:30:12.011Z","updated_at":"2025-04-04T15:07:59.338Z","avatar_url":"https://github.com/DingpingZhang.png","language":"C#","readme":"# WpfExtensions\n\nEnglish | [中文](./README.zh-CN.md)\n\nThis project comes from some scattered works I did while working on Wpf development, and is a supplement to existing Mvvm frameworks. They don't solve any major problems, they just provide some syntactic sugar and let people write a few lines of code less. Its services are not limited to Wpf development, other similar Xaml frameworks, such as Uwp, Maui, etc. should also be able to use, but I has never tested on other frameworks.\n\nThe project is structured as follows:\n\n- `WpfExtensions.Xaml`：A number of `MarkupExtension`s are provided to simplify Xaml development.\n- `WpfExtensions.Binding`：To simplify the code for property dependency updates, a function similar to the one in Vue.js for computed-property is provided.\n- `WpfExtensions.Infrastructure`：Some scattered features, when the time is ripe, will be separated out and released as separate modules.\n\n## NuGet\n\n| Package                 | NuGet                                                                                                                   |\n| ----------------------- | ----------------------------------------------------------------------------------------------------------------------- |\n| `WpfExtensions.Xaml`    | [![version](https://img.shields.io/nuget/v/WpfExtensions.Xaml.svg)](https://www.nuget.org/packages/WpfExtensions.Xaml) |\n| `WpfExtensions.Binding` | [![version](https://img.shields.io/nuget/v/WpfExtensions.Binding.svg)](https://www.nuget.org/packages/WpfExtensions.Binding)   |\n\n## 1. WpfExtensions.Binding\n\nBrings some of the functionality of the Reactivity module from [Vue3](https://vuejs.org/api/) into Wpf.\n\n\u003e The term \"observable\" as used in the following documentation refers to objects that implement `INotifyPropertyChanged` or `INotifyCollectionChanged`.\n\n### 1.1 `Watch`\n\nSubscribe to an observable expression and trigger a callback function when its value changes.\n\n```csharp\n// See the source code for more overloads, whose signatures are consistent with vue3's `watch()`, and the vue3 documentation for examples.\nReactivity.Default.Watch(() =\u003e Width * Height, area =\u003e Debug.WriteLine(area));\n```\n\n### 1.2 `WatchDeep`\n\nDeep traversal subscribes to an observable object and triggers a callback function when its properties, or the properties of its properties, change.\n\n```csharp\n// `path` will print out the path to the specific property that was changed.\nReactivity.Default.WatchDeep(obj, path =\u003e Debug.WriteLine(path))\n```\n\n### 1.3 `Computed`\n\nComputed property that is an instance method of the `BindableBase` base class.\n\n```csharp\npublic class ViewModel : BindableBase {\n    // Can be bound to xaml to automatically notify Area changes when Width or Height changes.\n    public double Area =\u003e Computed(() =\u003e Width * Height);\n}\n```\n\n## 2. WpfExtensions.Xaml\n\n## 0. **\\*New** `CommandExtension`\n\n- View (XAML):\n\n```xml\n\u003cElement Command={markup:Command Execute} /\u003e\n\u003cElement Command={markup:Command ExecuteWithArgumentAsync, CanExecute}\n         CommandParameter={Binding Argument} /\u003e\n```\n\n- View Model (\\*.cs):\n\n```csharp\nclass ViewModel\n{\n    public void Execute() {}\n\n    public void ExecuteWithArgument(string arg) {}\n\n    // The `Execute` method supports async, and its default `Can Execute` method will disable the command when it is busy.\n\n    public Task ExecuteAsync() =\u003e Task.Completed;\n\n    public Task ExecuteWithArgumentAsync(string arg) =\u003e Task.Completed;\n\n    // The `Can Execute` method does not support async.\n\n    public bool CanExecute() =\u003e true;\n\n    public bool CanExecuteWithArgument(string arg) =\u003e true;\n}\n```\n\n## 1. `ComposeExtension`\n\nCombine multiple Converters into one pipeline.\n\n```xml\n\u003cTextBlock Visibility=\"{Binding DescriptionText, Converter={markup:Compose\n                       {StaticResource IsNullOrEmptyOperator},\n                       {StaticResource NotConverter},\n                       {StaticResource BooleanToVisibilityConverter}}}\"\n           Text=\"{Binding DescriptionText}\" /\u003e\n```\n\n## 2. `IfExtension`\n\nUsing the `Conditional expression` in XAML.\n\n```xml\n\u003cButton Command=\"{markup:If {Binding BoolProperty},\n                            {Binding OkCommand},\n                            {Binding CancelCommand}}\" /\u003e\n```\n\n```xml\n\u003cUserControl\u003e\n    \u003cmarkup:If Condition=\"{Binding IsLoading}\"\u003e\n        \u003cmarkup:If.True\u003e\n            \u003cviews:LoadingView /\u003e\n        \u003c/markup:If.True\u003e\n        \u003cmarkup:If.False\u003e\n            \u003cviews:LoadedView /\u003e\n        \u003c/markup:If.False\u003e\n    \u003c/markup:If\u003e\n\u003c/UserControl\u003e\n```\n\n## 3. `SwitchExtension`\n\nUsing the `Switch expression` in XAML.\n\n```xml\n\u003cImage Source=\"{markup:Switch {Binding FileType},\n                              {Case {x:Static res:FileType.Music}, {StaticResource MusicIcon}},\n                              {Case {x:Static res:FileType.Video}, {StaticResource VideoIcon}},\n                              {Case {x:Static res:FileType.Picture}, {StaticResource PictureIcon}},\n                              ...\n                              {Case {StaticResource UnknownFileIcon}}}\" /\u003e\n```\n\n```xml\n\u003cUserControl\u003e\n    \u003cSwitch To=\"{Binding SelectedViewName}\"\u003e\n        \u003cCase Label=\"View1\"\u003e\n            \u003cviews:View1 /\u003e\n        \u003c/Case\u003e\n        \u003cCase Label=\"{x:Static res:Views.View2}\"\u003e\n            \u003cviews:View2 /\u003e\n        \u003c/Case\u003e\n        \u003cCase\u003e\n            \u003cviews:View404 /\u003e\n        \u003c/Case\u003e\n    \u003c/Switch\u003e\n\u003c/UserControl\u003e\n```\n\n## 4. `I18nExtension`\n\nDynamically switch the culture resource without restarting the app.\n\n```xml\n\u003cTextBlock Text=\"{markup:I18n {x:Static languages:UiStrings.MainWindow_Title}}\" /\u003e\n\u003cTextBlock Text=\"{markup:I18nString {x:Static languages:UiStrings.SayHello}, {Binding Username}}\" /\u003e\n\u003cTextBlock Text=\"{markup:I18nString {x:Static languages:UiStrings.StringFormat},\n                                    {Binding Arg0},\n                                    {Binding Arg1},\n                                    ...,\n                                    {Binding Arg15}}\" /\u003e\n```\n\n## 5. `StylesExtension` (In Progress)\n\n```xml\n\u003cButton Style=\"{markup:Styles {StaticResource FlatButtonStyle},\n                              {StaticResource AnimationStyle},\n                              ...}\" /\u003e\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdingpingzhang%2Fwpfextensions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdingpingzhang%2Fwpfextensions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdingpingzhang%2Fwpfextensions/lists"}