├── .gitattributes ├── .gitignore ├── BlazorBinding.sln ├── BlazorBinding ├── App.razor ├── BlazorBinding.csproj ├── Components │ ├── AutoComplete │ │ └── AutoComplete.razor │ ├── BlazorComponentExt.cs │ ├── CheckBox.razor │ ├── CheckBox2.razor │ ├── CheckBox3.razor │ ├── CheckBox4.razor │ ├── CheckBox5.razor │ ├── CheckBox6.razor │ ├── DocumentationSupport │ │ ├── Card.razor │ │ ├── ChangeLogItems.cs │ │ ├── DisplayCode.md │ │ └── DisplayCode.razor │ ├── ListView.razor │ ├── MMDialog.razor │ ├── ModelAttribute.cs │ └── _Imports.razor ├── Models │ ├── DataModel.cs │ ├── ISampleData.cs │ └── SampleUserData.cs ├── Pages │ ├── CascadeCallback.razor │ ├── CascadeCallback.razor.cs │ ├── DialogDemo.razor │ ├── Index.razor │ ├── Readme.razor │ ├── SimpleBinding.razor │ ├── SimpleBindingCallback.razor │ ├── SimpleCascade.razor │ ├── Suggestion.razor │ ├── TheProblemWithClicks.razor │ ├── ValueBinding.razor │ ├── ValueBindingCallback.razor │ ├── ValueBindingCallbackRefresh.razor │ ├── ValueBindingClassCallbackRefresh.razor │ ├── ViewModelBinding.razor │ └── _Imports.razor ├── Program.cs ├── Properties │ ├── PublishProfiles │ │ └── MagooBlazor - Web Deploy.pubxml │ └── launchSettings.json ├── Services │ ├── CodeHighlighter.cs │ └── ICodeHighlighter.cs ├── Shared │ ├── MainLayout.razor │ └── NavMenu.razor ├── Startup.cs ├── _Imports.razor └── wwwroot │ ├── browserconfig.xml │ ├── css │ ├── bootstrap │ │ ├── bootstrap.min.css │ │ └── bootstrap.min.css.map │ ├── open-iconic │ │ ├── FONT-LICENSE │ │ ├── ICON-LICENSE │ │ ├── README.md │ │ └── font │ │ │ ├── css │ │ │ └── open-iconic-bootstrap.min.css │ │ │ └── fonts │ │ │ ├── open-iconic.eot │ │ │ ├── open-iconic.otf │ │ │ ├── open-iconic.svg │ │ │ ├── open-iconic.ttf │ │ │ └── open-iconic.woff │ └── site.css │ ├── data │ ├── README.md │ └── changelog.json │ ├── images │ ├── android-icon-144x144.png │ ├── android-icon-192x192.png │ ├── android-icon-36x36.png │ ├── android-icon-48x48.png │ ├── android-icon-512x512.png │ ├── android-icon-72x72.png │ ├── android-icon-96x96.png │ ├── apple-icon-114x114.png │ ├── apple-icon-120x120.png │ ├── apple-icon-144x144.png │ ├── apple-icon-152x152.png │ ├── apple-icon-180x180.png │ ├── apple-icon-57x57.png │ ├── apple-icon-60x60.png │ ├── apple-icon-72x72.png │ ├── apple-icon-76x76.png │ ├── apple-icon-precomposed.png │ ├── apple-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon-96x96.png │ ├── favicon.ico │ ├── ms-icon-144x144.png │ ├── ms-icon-150x150.png │ ├── ms-icon-310x310.png │ └── ms-icon-70x70.png │ ├── index.html │ ├── js │ └── Helpers.js │ └── manifest.json ├── Directory.Build.props └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /BlazorBinding.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.168 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorBinding", "BlazorBinding\BlazorBinding.csproj", "{A2454D7F-581C-4784-ADC0-BA3F227AC66E}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{57B74E98-1E09-4CE2-B9CC-C46593CF8DC9}" 9 | ProjectSection(SolutionItems) = preProject 10 | Directory.Build.props = Directory.Build.props 11 | README.md = README.md 12 | EndProjectSection 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {A2454D7F-581C-4784-ADC0-BA3F227AC66E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {A2454D7F-581C-4784-ADC0-BA3F227AC66E}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {A2454D7F-581C-4784-ADC0-BA3F227AC66E}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {A2454D7F-581C-4784-ADC0-BA3F227AC66E}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {4906637B-B8E9-47EF-A3C3-0018A3B5152F} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /BlazorBinding/App.razor: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Components.Routing 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

Sorry, there's nothing at this address.

10 |
11 |
12 |
13 | 14 | -------------------------------------------------------------------------------- /BlazorBinding/BlazorBinding.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.1 5 | latest 6 | 3.0 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /BlazorBinding/Components/AutoComplete/AutoComplete.razor: -------------------------------------------------------------------------------- 1 |  2 |
3 | 4 | @if (suggestions?.Count > 0) 5 | { 6 |
7 | 19 |
20 | } 21 |
22 | 23 | 24 | @code 25 | { 26 | [Parameter] public IEnumerable AllowedValues { get; set; } 27 | [Parameter] public RenderFragment ListItemContent { get; set; } 28 | 29 | [Inject] HttpClient httpClient { get; set; } 30 | 31 | List suggestions; 32 | string data; 33 | Task worker; 34 | string[] PageContents; 35 | 36 | async Task HideDropdown(FocusEventArgs args) 37 | { 38 | suggestions?.Clear(); 39 | await Task.FromResult(true); 40 | } 41 | 42 | async Task InputChanged(ChangeEventArgs args) 43 | { 44 | await Task.Delay(0); 45 | worker = ProcessInput(args.Value.ToString()); 46 | } 47 | 48 | async Task KeyPress(KeyboardEventArgs args) 49 | { 50 | if (suggestions?.Count == 0) 51 | return; 52 | if (args.Code == "ArrowDown") 53 | await SelectNextItem(); 54 | if (args.Code == "ArrowUp") 55 | await SelectPrevItem(); 56 | if (args.Code == "Enter") 57 | await HideDropdown(null); 58 | } 59 | 60 | async Task SelectItem(SuggestionItems item) 61 | { 62 | suggestions.ForEach(s => s.Selected = ""); 63 | item.Selected = "active"; 64 | await Task.FromResult(true); 65 | } 66 | 67 | async Task SelectNextItem() 68 | { 69 | int last = -1; 70 | for (int i = 0; i < suggestions.Count; i++) 71 | { 72 | var sugg = suggestions[i]; 73 | if (sugg.Selected?.Length > 0) 74 | { 75 | sugg.Selected = ""; 76 | last = i; 77 | break; 78 | } 79 | } 80 | last++; 81 | if (last >= suggestions.Count) 82 | { 83 | last = 0; 84 | } 85 | suggestions[last].Selected = "active"; 86 | data = suggestions[last].Title; 87 | await Task.FromResult(true); 88 | } 89 | 90 | async Task SelectPrevItem() 91 | { 92 | int last = suggestions.Count; 93 | for (int i = 0; i < suggestions.Count; i++) 94 | { 95 | var sugg = suggestions[i]; 96 | if (sugg.Selected?.Length > 0) 97 | { 98 | sugg.Selected = ""; 99 | last = i; 100 | break; 101 | } 102 | } 103 | last--; 104 | if (last < 0) 105 | { 106 | last = suggestions.Count; 107 | } 108 | suggestions[last].Selected = "active"; 109 | data = suggestions[last].Title; 110 | await Task.FromResult(true); 111 | } 112 | 113 | Task ProcessInput(string value) 114 | { 115 | suggestions = AllowedValues 116 | .Where(s => s?.StartsWith(value, StringComparison.OrdinalIgnoreCase) ?? false) 117 | .Take(20) 118 | .OrderBy(s => s) 119 | .Select(s => new SuggestionItems() { Value = s, Title = s }) 120 | .ToList(); 121 | //StateHasChanged(); 122 | return Task.CompletedTask; 123 | } 124 | 125 | public class SuggestionItems 126 | { 127 | public string Value; 128 | public string Selected; 129 | public string Title; 130 | public override string ToString() 131 | { 132 | return Title; 133 | } 134 | } 135 | 136 | protected async override Task OnParametersSetAsync() 137 | { 138 | await base.OnParametersSetAsync(); 139 | 140 | try 141 | { 142 | var stream = await httpClient.GetStringAsync("https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/master/BlazorBinding/Components/AutoComplete/AutoComplete.razor"); 143 | PageContents = stream.Split(Environment.NewLine.ToCharArray()); 144 | StateHasChanged(); 145 | } 146 | catch (Exception ex) 147 | { 148 | Console.WriteLine("Failed to load AutoComplete.razor"); 149 | Console.WriteLine(ex.GetBaseException().Message); 150 | } 151 | 152 | } 153 | } -------------------------------------------------------------------------------- /BlazorBinding/Components/BlazorComponentExt.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using System; 3 | using System.ComponentModel; 4 | using Blazor = Microsoft.AspNetCore.Components; 5 | 6 | namespace BlazorBinding.Components 7 | { 8 | public partial class BlazorComponentExt : ComponentBase 9 | { 10 | [Blazor.Parameter] public RenderFragment Body { get; set; } 11 | 12 | protected override void OnInitialized() 13 | { 14 | Console.WriteLine("MYINIT"); 15 | base.OnInitialized(); 16 | RegisterModels(GetType()); 17 | } 18 | 19 | private void RegisterModels(Type type) 20 | { 21 | Console.WriteLine("REGISTER"); 22 | var props = ((System.Reflection.TypeInfo)type).DeclaredProperties; 23 | foreach (var prop in props) 24 | { 25 | var attr = (ModelAttribute)Attribute.GetCustomAttribute(prop, typeof(ModelAttribute)); 26 | if (attr is null) 27 | { 28 | Console.WriteLine($"Property {prop.Name} is not a Model"); 29 | } 30 | else 31 | { 32 | Console.WriteLine($"Property {prop.Name} is a model called {prop.PropertyType.Name}"); 33 | var model = prop.GetValue(this); 34 | if (model is null) 35 | { 36 | Console.WriteLine("The model is null, newing up..."); 37 | model = Activator.CreateInstance(prop.PropertyType); 38 | prop.SetValue(this, model); 39 | } 40 | ((INotifyPropertyChanged)model).PropertyChanged += Vm_PropertyChanged; 41 | } 42 | } 43 | } 44 | 45 | private void Vm_PropertyChanged(object sender, PropertyChangedEventArgs e) 46 | { 47 | Console.WriteLine($"Property {e.PropertyName} changed on {sender.GetType().Name}"); 48 | StateHasChanged(); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /BlazorBinding/Components/CheckBox.razor: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | @code 6 | { 7 | [CascadingParameter(Name = "ParentValue")] bool Value { get; set; } 8 | } -------------------------------------------------------------------------------- /BlazorBinding/Components/CheckBox2.razor: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | @code { 6 | [CascadingParameter(Name = "ParentValue")] bool ParentValue { get; set; } 7 | 8 | bool Value { get { return ParentValue; } set { Callback?.Invoke(value); } } 9 | 10 | [Parameter] public Action Callback { get; set; } 11 | } -------------------------------------------------------------------------------- /BlazorBinding/Components/CheckBox3.razor: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | @code 6 | { 7 | [Parameter] public bool Value { get; set; } 8 | } -------------------------------------------------------------------------------- /BlazorBinding/Components/CheckBox4.razor: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | @code { 6 | [Parameter] public bool Value { get; set; } 7 | 8 | bool LocalValue { get { return Value; } set { Callback?.Invoke(value); } } 9 | 10 | [Parameter] public Action Callback { get; set; } 11 | } -------------------------------------------------------------------------------- /BlazorBinding/Components/CheckBox5.razor: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | @code { 6 | [Parameter] public bool Value { get; set; } 7 | 8 | [Parameter] public Action ValueChanged { get; set; } 9 | } -------------------------------------------------------------------------------- /BlazorBinding/Components/CheckBox6.razor: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | @code { 6 | bool LocalValue { get { return Value; } set { ValueChanged?.Invoke(value); } } 7 | 8 | [Parameter] public bool Value { get; set; } 9 | 10 | [Parameter] public Action ValueChanged { get; set; } 11 | } -------------------------------------------------------------------------------- /BlazorBinding/Components/DocumentationSupport/Card.razor: -------------------------------------------------------------------------------- 1 | 
2 |
@Header
3 |
4 |

@Introduction

5 | @ChildContent 6 |
7 |
8 | 9 | @functions { 10 | 11 | [Parameter] public string Header { get; set; } 12 | 13 | [Parameter] public string Introduction { get; set; } 14 | 15 | [Parameter] public RenderFragment ChildContent { get; set; } 16 | 17 | } -------------------------------------------------------------------------------- /BlazorBinding/Components/DocumentationSupport/ChangeLogItems.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace BlazorBinding.Components.DocumentationSupport 7 | { 8 | public class ChangeLog 9 | { 10 | public DateTime dated { get; set; } 11 | public string content { get; set; } 12 | public Child[] child { get; set; } 13 | } 14 | 15 | public class Child 16 | { 17 | public string text { get; set; } 18 | } 19 | 20 | } 21 | 22 | -------------------------------------------------------------------------------- /BlazorBinding/Components/DocumentationSupport/DisplayCode.md: -------------------------------------------------------------------------------- 1 | # DisplayCode enhancement 2 | 3 | *Update: 5th Dec 2018* 4 | *Much of this has now been replaced by the new DisplayCode component which does not use JSInterop* 5 | 6 | When I saw SQL Mister Magoo's excellent BlazorBinding project I thought it would be an 7 | interesting experiment to try to add Code Syntax Highlighting to his `` component. 8 | 9 | This turned out to be a bit tricker than I realised, since we had to permit Blazor to render the 10 | `ChildContent` render fragment first, and then grab the HTML via JS interop, and re-render 11 | using a .NET library. 12 | 13 | ### ColorCode 14 | 15 | I looked on [Nuget](https://nuget.org) for Syntax Highlighting packages that would work on 16 | .NET Standard (required since this is client-side Blazor), and found 17 | [ColorCode](https://github.com/WilliamABradley/ColorCode-Universal), which works very well and 18 | supports multiple languages. 19 | 20 | ### DisplayCode 21 | So I amended the `` component to add a unique ID to each code `
` so we 22 | could pull the `innerText` from the element, apply the syntax highlighting, and then re-render 23 | the text back. 24 | 25 | I added the file `wwwroot/js/displayCode.js` library to host the Javascript methods I needed, and 26 | added these to the `index.html` page. The helper methods `GetInnerText` and `SetInnerHTML` call the 27 | Javascript code. 28 | 29 | I also added an override for `OnAfterRenderAsync` which then grabs the raw inner text 30 | from the `div` and applies the syntax highlighting. 31 | 32 | I also added a new `[Parameter] string Languages {get;set;} = "html";` which 33 | defaults to HTML (since most examples use this), but allows the component to do 34 | highlighting for any of the 35 | [supported languages](https://github.com/WilliamABradley/ColorCode-Universal/blob/master/ColorCode.Core/Common/LanguageId.cs) 36 | 37 | Example: 38 | ``` 39 | 40 | @("") 41 | 42 | ``` 43 | ### Issues 44 | 45 | The `
` tag added a number of blank lines and I added the `CleanCode` method to trim these off, otherwise the code sample 
46 | has a lot of blank space above/below. There might be a better fix for this, as it would also remove intentionally blank lines within
47 | the code as well as at the start/end.
48 | 
49 | 
50 | 


--------------------------------------------------------------------------------
/BlazorBinding/Components/DocumentationSupport/DisplayCode.razor:
--------------------------------------------------------------------------------
 1 | @using BlazorBinding.Services
 2 | @inject ICodeHighlighter CodeHighlighter
 3 | 
 4 | @if (Code != null)
 5 | {
 6 |     
7 | @ToggleText code 8 | @if (displayCode) 9 | { 10 |
11 | @CodeMarkup 12 |
13 | } 14 |
15 | } 16 | 17 | @code 18 | { 19 | bool displayCode = false; 20 | [Parameter] public string Language { get; set; } = "HTML"; 21 | [Parameter] public string[] Code { get; set; } 22 | MarkupString cache; 23 | private MarkupString CodeMarkup 24 | { 25 | get 26 | { 27 | if (!string.IsNullOrWhiteSpace(cache.Value)) 28 | return cache; 29 | 30 | switch (Language.ToUpper()) 31 | { 32 | case "HTML": 33 | cache = (MarkupString)CodeHighlighter.HighlightHtml(string.Join("\n", Code)); 34 | return cache; 35 | case "CSHARP": 36 | cache = (MarkupString)CodeHighlighter.HighlightCSharp(string.Join("\n", Code)); 37 | return cache; 38 | } 39 | cache = (MarkupString)string.Join("\n", Code); 40 | return cache; 41 | } 42 | } 43 | 44 | string ToggleText => displayCode ? "hide" : "show"; 45 | void ToggleCode() 46 | { 47 | displayCode = !displayCode; 48 | StateHasChanged(); 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /BlazorBinding/Components/ListView.razor: -------------------------------------------------------------------------------- 1 | @typeparam TList 2 | 3 | @if (ListData == null) 4 | { 5 |
Nothing to display
6 | } 7 | else 8 | { 9 | foreach (var listItem in ListData) 10 | { 11 |
12 | 18 |
19 | 20 |
21 | } 22 | } 23 | 24 | @code 25 | { 26 | TList activeItem; 27 | 28 | [Parameter] public List ListData { get; set; } 29 | [Parameter] public Action> ListDataChanged { get; set; } 30 | [Parameter] public Action ChangeAction { get; set; } 31 | [Parameter] public RenderFragment ListItemContent { get; set; } 32 | 33 | string GetActive(TList item) 34 | { 35 | return item?.Equals(activeItem) ?? false ? "active" : ""; 36 | } 37 | 38 | void SelectItem(TList item) 39 | { 40 | activeItem = item; 41 | ChangeAction?.Invoke(item, "Selected"); 42 | StateHasChanged(); 43 | } 44 | 45 | void DeleteItem(TList item) 46 | { 47 | if (item.Equals(activeItem)) 48 | activeItem = default(TList); 49 | ListData.Remove(item); 50 | ChangeAction?.Invoke(item, "Deleted"); 51 | StateHasChanged(); 52 | } 53 | } -------------------------------------------------------------------------------- /BlazorBinding/Components/MMDialog.razor: -------------------------------------------------------------------------------- 1 |  2 | 49 | 50 | @code 51 | { 52 | 53 | [Parameter] public RenderFragment TitleContent { get; set; } 54 | [Parameter] public RenderFragment BodyContent { get; set; } 55 | [Parameter] public RenderFragment BtnPriContent { get; set; } 56 | [Parameter] public RenderFragment BtnSecContent { get; set; } 57 | [Parameter] public Action BtnPriClick { get; set; } 58 | [Parameter] public Action BtnSecClick { get; set; } 59 | 60 | ElementReference mmdialogref; 61 | string Classes = "modal fade"; 62 | string Styles = "display: none;"; 63 | string TitleText; 64 | string BodyText; 65 | string BtnPriText; 66 | string BtnSecText; 67 | 68 | #region "Public Actions" 69 | public void Show() 70 | { 71 | Classes = "modal fade show"; 72 | Styles = "display: block; padding-right: 17px;"; 73 | Console.WriteLine("SHOW"); 74 | StateHasChanged(); 75 | } 76 | public void Hide() 77 | { 78 | Classes = "modal fade"; 79 | Styles = "display: none;"; 80 | StateHasChanged(); 81 | } 82 | #endregion 83 | 84 | #region "Internal Actions" 85 | protected void BtnPriClickInternal(MouseEventArgs args) 86 | { 87 | if (BtnPriClick == null) 88 | { 89 | Console.WriteLine("Primary Button Self Closing"); 90 | Hide(); 91 | } 92 | else 93 | { 94 | Console.WriteLine("Primary Button Invoke"); 95 | BtnPriClick.Invoke(args); 96 | } 97 | } 98 | protected void BtnSecClickInternal(MouseEventArgs args) 99 | { 100 | if (BtnSecClick == null) 101 | { 102 | Console.WriteLine("Secondary Button Self Closing"); 103 | Hide(); 104 | } 105 | else 106 | { 107 | Console.WriteLine("Secondary Button Invoke"); 108 | BtnSecClick.Invoke(args); 109 | } 110 | } 111 | protected void CloseDialog(MouseEventArgs args) 112 | { 113 | Console.WriteLine("Close Button"); 114 | Hide(); 115 | } 116 | #endregion 117 | 118 | #region "Public Setters" 119 | public void SetTitle(string Title) 120 | { 121 | Console.WriteLine($"New Title: {Title}"); 122 | TitleText = Title; 123 | } 124 | public void SetBody(string Body) 125 | { 126 | Console.WriteLine($"New Body: {Body}"); 127 | BodyText = Body; 128 | } 129 | public void SetBtnPriText(string Btn) 130 | { 131 | Console.WriteLine($"New Pri: {Btn}"); 132 | BtnPriText = Btn; 133 | } 134 | public void SetBtnSecText(string Btn) 135 | { 136 | Console.WriteLine($"New Sec: {Btn}"); 137 | BtnSecText = Btn; 138 | } 139 | public void SetBtnPriCallback(Action Callback) 140 | { 141 | BtnPriClick = Callback; 142 | } 143 | public void SetBtnSecCallback(Action Callback) 144 | { 145 | BtnSecClick = Callback; 146 | } 147 | #endregion 148 | 149 | protected override void OnInitialized() 150 | { 151 | if (TitleContent == null && TitleText == null) SetTitle("Information"); 152 | if (BodyContent == null && BodyText == null) SetBody("This is a sample dialog, with default values."); 153 | if (BtnPriText == null && BtnPriText == null) SetBtnPriText("OK"); 154 | if (BtnSecText == null && BtnSecText == null) SetBtnSecText("Cancel"); 155 | } 156 | // 157 | } 158 | -------------------------------------------------------------------------------- /BlazorBinding/Components/ModelAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace BlazorBinding.Components 4 | { 5 | [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] 6 | sealed class ModelAttribute : Attribute 7 | { 8 | public ModelAttribute() { } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /BlazorBinding/Components/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Components.Web -------------------------------------------------------------------------------- /BlazorBinding/Models/DataModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace BlazorBinding.Models 5 | { 6 | class DataModel : INotifyPropertyChanged 7 | { 8 | public event PropertyChangedEventHandler PropertyChanged; 9 | bool _toggle; 10 | 11 | public bool Toggle 12 | { 13 | get => _toggle; 14 | set 15 | { 16 | if (value != _toggle) 17 | { 18 | _toggle = value; 19 | RaisePropertyChanged(); 20 | } 21 | } 22 | } 23 | 24 | private void RaisePropertyChanged([CallerMemberName] string name = null) 25 | { 26 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /BlazorBinding/Models/ISampleData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace BlazorBinding.Models 7 | { 8 | public interface ISampleData 9 | { 10 | int Id { get; } 11 | string Name { get; set; } 12 | string NickName { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /BlazorBinding/Models/SampleUserData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace BlazorBinding.Models 7 | { 8 | public class SampleUserData : ISampleData 9 | { 10 | public SampleUserData() 11 | { 12 | } 13 | 14 | public SampleUserData(string Name, string NickName) 15 | { 16 | this.Name = Name; 17 | this.NickName = NickName; 18 | } 19 | 20 | public int Id { get; } 21 | public string Name { get ; set ; } 22 | public string NickName { get ; set ; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /BlazorBinding/Pages/CascadeCallback.razor: -------------------------------------------------------------------------------- 1 | @page "/cc" 2 | @inherits CascadeCallbackModel 3 | 4 |

Cascading Value With Callback - "Two Way Binding"

5 |
6 |
This is the parent control
7 |
8 |

Try clicking the checkbox - the second checkbox will also change because of the CascadingValue.

9 |
10 | 11 | 12 | 13 | 14 |
15 | "})"/> 16 |
17 |
18 | 19 |
20 |
This is the Child control
21 |
22 |

This is the child control, try clicking the checkbox - it will update the parent Value.

23 |
24 | 25 | 26 | 27 | 28 | 29 |
30 | ", 32 | " ", 33 | "", 34 | })"/> 35 |

36 | The CheckBox2 implementation : 37 |

38 |

39 | Here we bind to a local proxy value so we can fire the Callback when the local value changes 40 |

41 | "})" /> 42 | Callback { get; set; }" , 46 | " [CascadingParameter(Name =\" ParentValue\")] bool ParentValue { get; set; }", 47 | " bool Value { get { return ParentValue; } set { Callback?.Invoke(value); } }" , 48 | "}" , 49 | })" /> 50 |
51 |
52 |

53 | Page implementation: 54 |

55 | StateHasChanged();", 60 | " void UpdateValue(bool value) { ParentValue = value; Refresh(null); }", 61 | "}", 62 | })" /> 63 | 64 | @*
65 |

Event List (@EventList.Count)

66 | @GetEvents() 67 |
*@ -------------------------------------------------------------------------------- /BlazorBinding/Pages/CascadeCallback.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using Microsoft.AspNetCore.Components.Web; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace BlazorBinding.Pages 8 | { 9 | 10 | public class CascadeCallbackModel : ComponentBase 11 | { 12 | private bool _parentValue; 13 | internal bool ParentValue 14 | { 15 | get 16 | { 17 | return _parentValue; 18 | } 19 | set 20 | { 21 | AddEvent("Parent", $"Set ParentValue: {value}"); 22 | _parentValue = value; 23 | } 24 | } 25 | 26 | internal void AddEvent(string Entity,string Value) 27 | { 28 | EventList.Add($"{Entity} - {DateTime.Now.ToLongTimeString()} : {Value}"); 29 | } 30 | 31 | internal void Refresh(MouseEventArgs args) 32 | { 33 | AddEvent("Parent", $"Refresh: {args?.Type ?? "page"}"); 34 | StateHasChanged(); 35 | } 36 | 37 | internal void UpdateValue(bool value) 38 | { 39 | AddEvent("Parent", $"UpdateValue : {value}"); 40 | ParentValue = value; 41 | Refresh(null); 42 | } 43 | 44 | internal string StateHasChangedCss => ParentValue ? "ping-on" : "ping-off"; 45 | 46 | internal List EventList = new List(); 47 | 48 | internal MarkupString GetEvents() 49 | { 50 | if (EventList?.Count == 0) 51 | return (MarkupString)string.Empty; 52 | 53 | StringBuilder events = new StringBuilder(); 54 | string last = EventList?.Count > 0 ? EventList[0] : string.Empty; 55 | string curr = string.Empty; 56 | int count = 0; 57 | foreach (var item in EventList) 58 | { 59 | curr = item; 60 | if (!curr.Equals(last,StringComparison.Ordinal)) 61 | { 62 | events.Append($"{last} ( x {count} )
"); 63 | count = 0; 64 | } 65 | last = curr; 66 | count++; 67 | } 68 | events.Append($"{last} ( x {count} )
"); 69 | return (MarkupString)events.ToString(); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /BlazorBinding/Pages/DialogDemo.razor: -------------------------------------------------------------------------------- 1 | @page "/dia" 2 | 3 |

Using CascadingValue To Share A Global Component - Dialog

4 |
5 |
Sample form for customising the modal dialog - simple local binding.
6 |
7 |
8 | 9 | 10 |
11 |
12 | 13 | 14 |
15 |
16 | 17 | 18 | @if (string.IsNullOrWhiteSpace(BtnPri)) 19 | { 20 |
21 | 22 | 23 |
24 | } 25 |
26 |
27 | 28 | 29 | @if (string.IsNullOrWhiteSpace(BtnSec)) 30 | { 31 |
32 | 33 | 34 |
35 | } 36 |
37 | 38 | @if (!string.IsNullOrWhiteSpace(Message)) 39 | { 40 |

@Message

41 | } 42 | 43 | 80 |
81 |
82 | 83 | @code 84 | { 85 | [CascadingParameter(Name = "Global")] MainLayout global { get; set; } 86 | 87 | string Title; 88 | string Body; 89 | string BtnPri; bool HidePri; 90 | string BtnSec; bool HideSec; 91 | string Message; 92 | 93 | void Clicked(MouseEventArgs args) 94 | { 95 | if (global == null) 96 | { 97 | Console.WriteLine($"CLICKED No Dialog"); 98 | return; 99 | } 100 | if (!string.IsNullOrWhiteSpace(Title)) 101 | global.MMDialogRef.SetTitle(Title); 102 | 103 | if (!string.IsNullOrWhiteSpace(Body)) 104 | global.MMDialogRef.SetBody(Body); 105 | 106 | if (!string.IsNullOrWhiteSpace(BtnPri) || HidePri) 107 | global.MMDialogRef.SetBtnPriText(BtnPri); 108 | 109 | if (!string.IsNullOrWhiteSpace(BtnSec) || HideSec) 110 | global.MMDialogRef.SetBtnSecText(BtnSec); 111 | 112 | global.MMDialogRef.SetBtnPriCallback(BtnPriCallback); 113 | global.MMDialogRef.SetBtnSecCallback(BtnSecCallback); 114 | 115 | global.MMDialogRef.Show(); 116 | Console.WriteLine($"TITLE: {Title}"); 117 | Console.WriteLine($"BODY : {Body}"); 118 | Console.WriteLine($"BTN 1: {BtnPri}"); 119 | Console.WriteLine($"BTN 2: {BtnSec}"); 120 | } 121 | protected void BtnPriCallback(MouseEventArgs args) 122 | { 123 | Message = $"User clicked dialog button 1 - {BtnPri}"; 124 | global?.MMDialogRef?.Hide(); 125 | StateHasChanged(); 126 | } 127 | protected void BtnSecCallback(MouseEventArgs args) 128 | { 129 | Message = $"User clicked dialog button 2 - {BtnSec}"; 130 | global?.MMDialogRef?.Hide(); 131 | StateHasChanged(); 132 | } 133 | 134 | } -------------------------------------------------------------------------------- /BlazorBinding/Pages/Index.razor: -------------------------------------------------------------------------------- 1 | @page "/" 2 | @using System.Text.Json 3 | 4 |
5 |

Data Binding Examples

6 |
7 |

8 | This is a working example of various binding techniques for Blazor. 9 |

10 |

11 | Please use the menu to work through the different options - if you work down the list, I think you will see how we have to accomodate the fact there are some issues in data-binding in Blazor. 12 |

13 |

14 | The code is on GitHub Blazor Binding Source 15 |

16 |
17 |
18 | 19 | 20 | @if (ChangeLogItems != null) 21 | { 22 | @foreach (var item in ChangeLogItems) 23 | { 24 |
25 |
@item.dated.ToLongDateString()
26 |
27 |

@((MarkupString)item.content)

28 | @if (item.child != null) 29 | { 30 | foreach (var child in item.child) 31 | { 32 |
33 | @((MarkupString)child.text) 34 |
35 | } 36 | } 37 |
38 |
39 | } 40 | } 41 | 42 | @functions 43 | { 44 | // 45 | [Inject] HttpClient httpClient { get; set; } 46 | ChangeLog[] ChangeLogItems; 47 | 48 | protected async override Task OnInitializedAsync() 49 | { 50 | await base.OnInitializedAsync(); 51 | try 52 | { 53 | var changeLogString = await httpClient.GetStringAsync("data/changelog.json"); 54 | var changeLogItems = JsonSerializer.Deserialize(changeLogString); 55 | ChangeLogItems = changeLogItems; 56 | Console.WriteLine($"Got {ChangeLogItems.Length} ChangeLogItems"); 57 | } 58 | catch (Exception e) 59 | { 60 | Console.WriteLine($"ERROR: {e.GetBaseException().Message}"); 61 | } 62 | } 63 | 64 | // 65 | } -------------------------------------------------------------------------------- /BlazorBinding/Pages/Readme.razor: -------------------------------------------------------------------------------- 1 | @page "/readme" 2 |
3 | @Contents 4 |
5 | 6 | @code 7 | { 8 | // 9 | [Inject] HttpClient httpClient { get; set; } 10 | MarkupString Contents; 11 | 12 | protected async override Task OnInitializedAsync() 13 | { 14 | await base.OnInitializedAsync(); 15 | try 16 | { 17 | var stream = await httpClient.GetStringAsync("https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/master/README.md"); 18 | Contents = (MarkupString)Markdig.Markdown.ToHtml(stream); 19 | } 20 | catch (Exception ex) 21 | { 22 | Console.WriteLine("Failed to load README.md"); 23 | Console.WriteLine(ex.GetBaseException().Message); 24 | Contents = (MarkupString)Markdig.Markdown.ToHtml("# BlazorBinding\n" + 25 | "Sample Blazor App demonstrating various data binding scenarios\n" + 26 | "\n" + 27 | "## Simple Cascade\n" + 28 | "Demonstrates how CascadingValue is a one-way data transfer, which updates the subscriber but not the publisher.\n" + 29 | "\n" + 30 | "## Cascade With Callback\n" + 31 | "Demonstrates how you can add a Callback Action to update the CascadingValue from subscriber to publisher.\n" + 32 | "\n" + 33 | "## Simple Binding\n" + 34 | "Demonstrates the use of parameter binding, which is a one-way binding like the CascadingValue, but specific to the bound Component.\n" + 35 | "\n" + 36 | "## Simple Binding With Callback\n" + 37 | "Demonstrates how you can add a Callback Action to update the parent values from the child.\n" + 38 | "\n" + 39 | "## Value Binding\n" + 40 | "Demonstrates how the bind-Value syntax works in a one-way mode, like simple binding.\n" + 41 | "*This is considered to be a bug by many*\n" + 42 | "\n" + 43 | "## Value Binding With Callback\n" + 44 | "Demonstrates how you can update the parent from a child component by invoking the _required_ ValueChanged Action.\n" + 45 | "\n" + 46 | "## Value Binding With Callback + Refresh\n" + 47 | "Demonstrates how you can ensure the parent knows a child component has updated data, and trigger a refresh.\n" + 48 | "\n" + 49 | "## Value Binding Class Object" + 50 | "Demonstrates how to two-way bind a list of objects with multiple properties." + 51 | "\n" + 52 | "## The Problem With Clicks - \"Propagation\"\n" + 53 | "Demonstrates how events on standard html elements propagate in Blazor. This is very bad.\n" + 54 | "\n" + 55 | "## Using CascadingValue To Share A Global Component - Dialog\n" + 56 | "Demonstrates how to use CascadingValue to share a component from MainLayout so that it is globally accessible.\n" + 57 | "\n" + 58 | "## Autocomplete text input" + 59 | "Demonstrates how to perform autocomplete on a text input." + 60 | "\n" + 61 | "## ViewModel Binding" + 62 | "Demonstrates a simple method to enable a page to bind a ViewModel that automatically hooks into StateHasChanged." + 63 | "\n" + 64 | "### Summary\n" + 65 | "\n" + 66 | "In all cases, some kind of callback action is required to notify the parent component of a change in the data.\n" + 67 | "This is, in my opinion OK - as it gives me control of the data and UI - however, some people consider the manual intervention required to be a bug.\n" + 68 | "\n" + 69 | "I have not included any examples of using \"State\" to achieve two way binding, although that is also possible, it would also require some kind of callback notification.\n" + 70 | ""); 71 | } 72 | } 73 | 74 | // 75 | } -------------------------------------------------------------------------------- /BlazorBinding/Pages/SimpleBinding.razor: -------------------------------------------------------------------------------- 1 | @page "/sb" 2 | 3 |

Simple Binding Value - "One Way Binding"

4 |
5 |
This is the parent control
6 |
7 |

The second checkbox will also change because of the Value parameter.

8 |
9 | 10 | 11 | 12 | 13 |
14 | 15 | "})"/> 16 |
17 |
18 |
19 |
This is the Child control
20 |
21 |

Try clicking the checkbox - it will not update the parent Value.

22 |
23 | 24 | 25 | 26 |
27 | ", 29 | })"/> 30 |

31 | The CheckBox3 implementation :

32 | ", 34 | })"/> 35 | 40 |
41 |
42 |
43 |
Invoking StateHasChanged
44 |
45 |
46 |
47 |
48 | Last refresh @DateTime.Now 49 |
50 |
51 |
52 | 53 |
54 |
55 |

56 | Now click the button to refresh this page - nothing will change except the Last Refresh time, because the Value parameter is a one-way binding. 57 |

58 | Refresh", 60 | })" /> 61 |
62 |
63 |

64 | Page implementation: 65 |

66 | StateHasChanged();", 70 | "}", 71 | })"/> 72 | 73 | @functions 74 | { 75 | bool ParentValue; 76 | void Refresh(MouseEventArgs args) => StateHasChanged(); 77 | string StateHasChangedCss => ParentValue ? "ping-on" : "ping-off"; 78 | } 79 | -------------------------------------------------------------------------------- /BlazorBinding/Pages/SimpleBindingCallback.razor: -------------------------------------------------------------------------------- 1 | @page "/sbc" 2 |

Simple Binding With Callback - "Two Way Binding"

3 |
4 |
This is the parent control
5 |
6 |

Try clicking the checkbox - the second checkbox will also change because of the Value parameter.

7 |
8 | 9 | 10 | 11 | 12 |
13 | "})"/> 14 |
15 |
16 | 17 |
18 |
This is the Child control
19 |
20 |

This is the child control, try clicking the checkbox - it will update the parent Value.

21 |
22 | 23 | 24 | 25 |
26 | "})"/> 27 |

The CheckBox4 implementation :

28 |

Here we bind to a local proxy value so we can fire the Callback when the local value changes.

29 | ", 30 | "@functions {", 31 | "[Parameter] public bool Value { get; set; }", 32 | "[Parameter] public Action Callback { get; set; }", 33 | "bool LocalValue { get { return Value; } set { Callback?.Invoke(value); } }", 34 | "}" 35 | })"/> 36 |
37 |
38 |
39 |
Invoking StateHasChanged
40 |
41 |
42 |
43 |
44 | Last refresh @DateTime.Now 45 |
46 |
47 |
48 | 49 |
50 |
51 |

52 | Page implementation: 53 |

54 |

55 | Now click the button to refresh this page - nothing will change except the Last Refresh time, because we are propogating the value back from Child to Parent and refreshing the Parent. 56 |

57 | Refresh", 59 | "@functions {", 60 | "bool ParentValue;", 61 | "void Refresh(MouseEventArgs args) => StateHasChanged();", 62 | "void UpdateValue(bool value) { ParentValue = value; Refresh(null); })", 63 | "}" 64 | })"/> 65 |
66 |
67 | 68 | @code 69 | { 70 | bool ParentValue; 71 | void Refresh(MouseEventArgs args) => StateHasChanged(); 72 | void UpdateValue(bool value) { ParentValue = value; Refresh(null); } 73 | string StateHasChangedCss => ParentValue ? "ping-on" : "ping-off"; 74 | } -------------------------------------------------------------------------------- /BlazorBinding/Pages/SimpleCascade.razor: -------------------------------------------------------------------------------- 1 | @page "/sc" 2 | 3 |

Simple Cascading Value - "One Way Binding"

4 | 5 |
6 |
This is the parent control
7 |
8 |

Try clicking the checkbox - the second checkbox will also change because of the CascadingValue.

9 |
10 | 11 | 12 | 13 | 14 |
15 | " 17 | })"/> 18 |
19 |
20 | 21 |
22 |
This is the Child control
23 |
24 |

Try clicking the checkbox - it will not update the parent Value.

25 |
26 | 27 | 28 | 29 | 30 | 31 |
32 | ", 34 | " ", 35 | "", 36 | })"/> 37 |

The CheckBox implementation :

38 | " 40 | })"/> 41 | 47 |
48 |
49 |
50 |
Invoking StateHasChanged
51 |
52 |
53 |
54 |
55 | Last refresh @DateTime.Now 56 |
57 |
58 |
59 | 60 |
61 |
62 |

63 | Now click the button to refresh this page - nothing will change except the Last Refresh time, because the CascadingValue is a one-way binding 64 |

65 | Refresh", 67 | })"/> 68 |
69 |
70 |

71 | Page implementation: 72 |

73 | StateHasChanged();", 78 | "}", 79 | })"/> 80 | 81 | @functions 82 | { 83 | 84 | bool ParentValue; 85 | void Refresh(MouseEventArgs args) => StateHasChanged(); 86 | string StateHasChangedCss => ParentValue ? "ping-on" : "ping-off"; 87 | 88 | } 89 | -------------------------------------------------------------------------------- /BlazorBinding/Pages/Suggestion.razor: -------------------------------------------------------------------------------- 1 | @page "/sugg" 2 | @using GenFu 3 | @using BlazorBinding.Components.AutoComplete 4 | 5 | @if (values == null) 6 | { 7 | Loading random list of names for the auto-complete list. 8 | } 9 | else 10 | { 11 | There are @values?.Count names in the auto-complete list. 12 | } 13 | 14 | 15 | 16 | @context 17 | 18 | 19 | 20 | Page Code 21 | 22 | @code 23 | { 24 | [Inject] HttpClient httpClient { get; set; } 25 | 26 | string[] PageContents; 27 | List values; 28 | 29 | protected override async Task OnParametersSetAsync() 30 | { 31 | await base.OnParametersSetAsync(); 32 | Task.Factory.StartNew(LoadData); 33 | } 34 | void LoadData() 35 | { 36 | values = A.ListOf(200).Select(p => $"{p.FirstName} {p.LastName}").Distinct().ToList(); 37 | Task.Factory.StartNew(async () => await LoadCode()); 38 | StateHasChanged(); 39 | } 40 | async Task LoadCode() 41 | { 42 | try 43 | { 44 | var stream = await httpClient.GetStringAsync("https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/master/BlazorBinding/Pages/Suggestion.cshtml"); 45 | PageContents = stream.Split(Environment.NewLine.ToCharArray()); 46 | StateHasChanged(); 47 | } 48 | catch (Exception ex) 49 | { 50 | Console.WriteLine("Failed to load Suggestion.cshtml"); 51 | Console.WriteLine(ex.GetBaseException().Message); 52 | } 53 | } 54 | class Person 55 | { 56 | public string FirstName { get; set; } 57 | public string LastName { get; set; } 58 | public Person() 59 | { 60 | 61 | } 62 | } 63 | // 64 | } 65 | -------------------------------------------------------------------------------- /BlazorBinding/Pages/TheProblemWithClicks.razor: -------------------------------------------------------------------------------- 1 | @page "/tpwc" 2 | 3 |

The Problem With Clicks - "Propagation"

4 | 5 |
6 |
This is the parent control
7 |
8 |

Try clicking the parent -

9 |
10 | 11 |
12 | ", 14 | })" /> 15 | ParentPingValue ? \"ping-on\" : \"ping-off\";", 19 | "void OnParentClick(MouseEventArgs args) => ParentPingValue = !ParentPingValue;", 20 | "}", 21 | })" /> 22 |
23 |
This is the child control
24 |
25 |

Try clicking the child and/or the hide/show code buttons and watch the parent.

26 |
27 | 28 |
29 | ", 31 | })" /> 32 | ChildPingValue ? \"ping-on\" : \"ping-off\";", 36 | "void OnChildClick(MouseEventArgs args) => ChildPingValue = !ChildPingValue;", 37 | "}", 38 | })" /> 39 |
40 |
This is the grandchild control
41 |
42 |

Try clicking the grandchild

43 |
44 | 45 |
46 | ", 48 | })" /> 49 | GrandChildPingValue ? \"ping-on\" : \"ping-off\";", 53 | "void OnGrandChildClick(MouseEventArgs args) => GrandChildPingValue = !GrandChildPingValue;", 54 | "}", 55 | })" /> 56 |
57 |
58 |
59 |
60 |
61 |
62 | 63 | @code 64 | { 65 | bool ParentPingValue; 66 | string ParentPingCss => ParentPingValue ? "ping-on" : "ping-off"; 67 | void OnParentClick(MouseEventArgs args) { ParentPingValue = !ParentPingValue; StateHasChanged(); } 68 | 69 | bool ChildPingValue; 70 | string ChildPingCss => ChildPingValue ? "ping-on" : "ping-off"; 71 | void OnChildClick(MouseEventArgs args) { ChildPingValue = !ChildPingValue; StateHasChanged(); } 72 | 73 | bool GrandChildPingValue; 74 | string GrandChildPingCss => GrandChildPingValue ? "ping-on" : "ping-off"; 75 | void OnGrandChildClick(MouseEventArgs args) { GrandChildPingValue = !GrandChildPingValue; StateHasChanged(); } 76 | } -------------------------------------------------------------------------------- /BlazorBinding/Pages/ValueBinding.razor: -------------------------------------------------------------------------------- 1 | @page "/vb" 2 | 3 |

Value Binding - "One Way Value Passing"

4 | 5 |
6 |
This is the parent control
7 |
8 |

Try clicking the checkbox - the second checkbox will also change because of the Value parameter.

9 |
10 | 11 | 12 | 13 | 14 |
15 | " 17 | })"/> 18 |
19 |
20 | 21 |
22 |
This is the Child control
23 |
24 |

Try clicking the checkbox - it will not update the parent Value.

25 |
26 | 27 | 28 | 29 |
30 | " 32 | })"/> 33 |

The CheckBox5 implementation :

34 |

The "ValueChanged" Action is required by the Blazor engine because we are using the bind-Value syntax.

35 | " 37 | })"/> 38 | ValueChanged { get; set; })", 43 | "}", 44 | })"/> 45 |
46 |
47 | 48 | 49 |
50 |
Invoking StateHasChanged
51 |
52 |
53 |
54 |
55 | Last refresh @DateTime.Now 56 |
57 |
58 |
59 | 60 |
61 |
62 |

63 | Now click the button to refresh this page - the child checkbox will revert back to match the parent value
64 | because we are doing nothing to propogate the value change from child to parent
65 | and Blazor does not do it for us, despite requiring the ValueChanged Action. 66 |

67 | Refresh", 69 | })"/> 70 |
71 |
72 |

73 | Page implementation: 74 |

75 | StateHasChanged();", 80 | "}", 81 | })"/> 82 | 83 | @functions 84 | { 85 | 86 | bool ParentValue; 87 | void Refresh(MouseEventArgs args) => StateHasChanged(); 88 | string StateHasChangedCss => ParentValue ? "ping-on" : "ping-off"; 89 | 90 | } 91 | -------------------------------------------------------------------------------- /BlazorBinding/Pages/ValueBindingCallback.razor: -------------------------------------------------------------------------------- 1 | @page "/vbc" 2 | 3 |

Value Binding With Callback - "Two Way Value Binding - No Refresh"

4 | 5 |
6 |
This is the parent control
7 |
8 |

Try clicking the checkbox - the second checkbox will also change because of the Value parameter.

9 |
10 | 11 | 12 | 13 | 14 |
15 | ", 17 | })"/> 18 |
19 |
20 | 21 |
22 |
This is the Child control
23 |
24 |

Try clicking the checkbox - it will not update the parent Value until you click Refresh below.

25 |
26 | 27 | 28 | 29 |
30 | ", 32 | })" /> 33 |

The CheckBox6 implementation :

34 |

We use a custom setter so we can fire the ValueChanged event when the local value changes.

35 |

Invoking the ValueChanged event is required in Blazor.

36 | ", 38 | })" /> 39 | ValueChanged { get; set; })", 45 | "}", 46 | })" /> 47 |
48 |
49 |
50 |
Invoking StateHasChanged
51 |
52 |
53 |
54 |
55 | Last refresh @DateTime.Now 56 |
57 |
58 |
59 | 60 |
61 |
62 |

63 | Now click the button to refresh this page - the Parent checkbox will revert back to match the Child's value
64 | because we are propogating the value change from child to parent but there is no automatic Refresh
65 | The value has propogated back from Child to Parent, but the parent has not refreshed. 66 |

67 | Refresh", 69 | })"/> 70 |
71 |
72 |

73 | Page implementation: 74 |

75 | StateHasChanged();", 80 | "}", 81 | })"/> 82 | 83 | 84 | @functions 85 | { 86 | 87 | bool ParentValue; 88 | void Refresh(MouseEventArgs args) => StateHasChanged(); 89 | string StateHasChangedCss => ParentValue ? "ping-on" : "ping-off"; 90 | 91 | } 92 | -------------------------------------------------------------------------------- /BlazorBinding/Pages/ValueBindingCallbackRefresh.razor: -------------------------------------------------------------------------------- 1 | @page "/vbcr" 2 | 3 |

Value Binding With Callback - "Two Way Value Binding - With Refresh"

4 | 5 |
6 |
This is the parent control
7 |
8 |

Try clicking the checkbox - the second checkbox will also change because of the @@bind-Value parameter.

9 |
10 | 11 | 12 | 13 | 14 |
15 | ", 17 | })"/> 18 |
19 |
20 |
21 |
This is the Child control
22 |
23 |

Try clicking the checkbox - it will update the parent Value.

24 |
25 | 26 | 27 | 28 |
29 | ", 31 | })"/> 32 |

The CheckBox6 implementation :

33 |

Here we bind to a local proxy value so we can fire the ValueChanged event when the local value changes.

34 | ", 36 | })"/> 37 | ValueChanged { get; set; })", 43 | "}", 44 | })"/> 45 |
46 |
47 |

48 | Page implementation: 49 |

50 | StateHasChanged();", 56 | "}", 57 | })" /> 58 | 59 | @functions 60 | { 61 | 62 | bool localParentValue; 63 | bool ParentValue { get { return localParentValue; } set { localParentValue = value; Refresh(null); } } 64 | protected void Refresh(MouseEventArgs args) { StateHasChanged(); } 65 | string StateHasChangedCss => ParentValue ? "ping-on" : "ping-off"; 66 | 67 | } 68 | -------------------------------------------------------------------------------- /BlazorBinding/Pages/ValueBindingClassCallbackRefresh.razor: -------------------------------------------------------------------------------- 1 | @using BlazorBinding.Models 2 | @page "/vbccr" 3 | 4 |

Value Binding a Class object With Callback - "Two Way Class Binding - With Refresh"

5 | 6 |
7 |
This is the parent control with @(data?.Count) items.
8 |
9 |

Try adding a new user, it should add them to the list.

10 |
11 | 12 | 13 | 14 | 15 |
16 |
17 | 18 |

@LastChange

19 |
20 |
21 |
22 | 27 |
28 |
29 |
30 | @@ 31 |
32 | 38 |
39 |
40 | 41 | 42 |
43 |
44 | ", 46 | "
", 47 | " ", 52 | "
", 53 | "
", 54 | "
", 55 | " @@", 56 | "
", 57 | " ", 63 | "
", 64 | "
", 65 | " ", 66 | " ", 67 | "
", 68 | "
", 69 | })" /> 70 |
71 | 72 | 73 | 74 |
75 |
This is the Child control with @(data?.Count) items.
76 |
77 | @*

Try editing a user - it will update the parent control.

*@ 78 |
79 | 80 | 81 | 82 |
@context.Name ( @($"@{context.NickName}") )
83 |
84 |
85 | 86 |
87 | ", 89 | " ", 90 | "
@context.Name @($\"@{context.NickName}\")
", 91 | "
", 92 | "", 93 | })" /> 94 |

The ListView implementation :

95 | Nothing to display
", 102 | "}", 103 | "else", 104 | "{", 105 | " foreach (var listItem in ListData)", 106 | " {", 107 | "
", 108 | " ", 114 | "
", 115 | " ", 116 | "
", 117 | " }", 118 | "}", 119 | })" /> 120 | ListData { get; set; }", 126 | " [Parameter] public Action> ListDataChanged { get; set; }", 127 | " [Parameter] public Action ChangeAction { get; set; }", 128 | " [Parameter] public RenderFragment ListItemContent { get; set; }", 129 | "", 130 | " string GetActive(TList item)", 131 | " {", 132 | " return item?.Equals(activeItem) ?? false ? \"active\" : \"\";", 133 | " }", 134 | "", 135 | " void SelectItem(TList item)", 136 | " {", 137 | " activeItem = item;", 138 | " ChangeAction?.Invoke(item, \"Selected\");", 139 | " StateHasChanged();", 140 | " }", 141 | "", 142 | " void DeleteItem(TList item)", 143 | " {", 144 | " if (item.Equals(activeItem))", 145 | " activeItem = default(TList);", 146 | " ListData.Remove(item);", 147 | " ChangeAction?.Invoke(item, \"Deleted\");", 148 | " StateHasChanged();", 149 | " }", 150 | "}", 151 | })" /> 152 | 153 | 154 |

155 | Page implementation: 156 |

157 | data = new List();", 165 | "", 166 | " void ListItemChanged(ISampleData item,string action)", 167 | " {", 168 | " LastChange = $\"User {item.Name} was {action} at {DateTime.Now}\";", 169 | " PingState = !PingState;", 170 | " StateHasChanged();", 171 | " }", 172 | "", 173 | " void AddNewUser(MouseEventArgs args)", 174 | " {", 175 | " AddingNewUser = \"\";", 176 | " PingState = !PingState;", 177 | " StateHasChanged();", 178 | " }", 179 | " void AddNewUserConfirm(MouseEventArgs args)", 180 | " {", 181 | " if (string.IsNullOrWhiteSpace(localName) ||", 182 | " string.IsNullOrWhiteSpace(localNick) ||", 183 | " data.Any(x => x.NickName.Equals(localNick, StringComparison.InvariantCultureIgnoreCase)))", 184 | " return;", 185 | "", 186 | " var newUser = new SampleUserData(localName, localNick);", 187 | " localName = \"\";", 188 | " localNick = \"\";", 189 | "", 190 | " data.Add(newUser);", 191 | " ListItemChanged(newUser, \"Added\");", 192 | " AddingNewUser = \"d-none\";", 193 | " StateHasChanged();", 194 | " }", 195 | " void AddNewUserCancel(MouseEventArgs args)", 196 | " {", 197 | " AddingNewUser = \"d-none\";", 198 | " PingState = !PingState;", 199 | " StateHasChanged();", 200 | " }", 201 | "}", 202 | })" /> 203 | 204 | @code 205 | { 206 | bool PingState; 207 | 208 | void Refresh(MouseEventArgs args) => StateHasChanged(); 209 | 210 | string StateHasChangedCss => PingState ? "ping-on" : "ping-off"; 211 | 212 | string LastChange; 213 | string AddingNewUser = "d-none"; 214 | string localName = ""; 215 | string localNick = ""; 216 | static List data = new List() { new SampleUserData("Test1", "TimmyTester") }; 217 | 218 | void ListItemChanged(ISampleData item, string action) 219 | { 220 | LastChange = $"User {item.Name} was {action} at {DateTime.Now}"; 221 | PingState = !PingState; 222 | StateHasChanged(); 223 | } 224 | 225 | void AddNewUser(MouseEventArgs args) 226 | { 227 | AddingNewUser = ""; 228 | PingState = !PingState; 229 | StateHasChanged(); 230 | } 231 | void AddNewUserConfirm(MouseEventArgs args) 232 | { 233 | if (string.IsNullOrWhiteSpace(localName) || 234 | string.IsNullOrWhiteSpace(localNick) || 235 | data.Any(x => x.NickName.Equals(localNick, StringComparison.InvariantCultureIgnoreCase))) 236 | return; 237 | 238 | var newUser = new SampleUserData(localName, localNick); 239 | localName = ""; 240 | localNick = ""; 241 | 242 | data.Add(newUser); 243 | ListItemChanged(newUser, "Added"); 244 | AddingNewUser = "d-none"; 245 | StateHasChanged(); 246 | } 247 | void AddNewUserCancel(MouseEventArgs args) 248 | { 249 | AddingNewUser = "d-none"; 250 | PingState = !PingState; 251 | StateHasChanged(); 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /BlazorBinding/Pages/ViewModelBinding.razor: -------------------------------------------------------------------------------- 1 | @page "/vm" 2 | @inherits BlazorComponentExt 3 |

View Model Binding - "Two Way Value Binding"

4 | 5 |
6 |
This is the parent control
7 |
8 |

Try clicking the checkbox - the second checkbox will also change because of the bound Value parameter.

9 |
10 | 11 | 12 | 13 | 14 |
15 | " 17 | })"/> 18 |
19 |
20 | 21 |
22 |
This is the Child control
23 |
24 |

Try clicking the checkbox - it will also update the parent Value because we are using a ViewModel.

25 |
26 | 27 | 28 | 29 |
30 | " 32 | })" /> 33 |

The CheckBox6 implementation :

34 |

We use a custom setter so we can fire the ValueChanged event when the local value changes.

35 |

Invoking the ValueChanged event is required in Blazor.

36 | ", 38 | })" /> 39 | ValueChanged { get; set; })", 45 | "}", 46 | })" /> 47 |
48 |
49 | 50 |

Page Functions

51 | StateHasChanged();", 56 | "}", 57 | })"/> 58 | @code 59 | { 60 | 61 | [ModelAttribute] BlazorBinding.Models.DataModel PageModel { get; set; } 62 | void Refresh(MouseEventArgs args) => StateHasChanged(); 63 | string StateHasChangedCss => PageModel.Toggle ? "ping-on" : "ping-off"; 64 | 65 | } 66 | -------------------------------------------------------------------------------- /BlazorBinding/Pages/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Components.Web 2 | @using BlazorBinding.Components 3 | @layout MainLayout -------------------------------------------------------------------------------- /BlazorBinding/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Blazor.Hosting; 2 | 3 | namespace BlazorBinding 4 | { 5 | public class Program 6 | { 7 | public static void Main(string[] args) 8 | { 9 | CreateHostBuilder(args).Build().Run(); 10 | } 11 | 12 | public static IWebAssemblyHostBuilder CreateHostBuilder(string[] args) => 13 | BlazorWebAssemblyHost.CreateDefaultBuilder() 14 | .UseBlazorStartup(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /BlazorBinding/Properties/PublishProfiles/MagooBlazor - Web Deploy.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | MSDeploy 9 | /subscriptions/d6eee2da-1a1f-402c-a05c-a70acd9c42b8/resourceGroups/Default-Web-NorthEurope/providers/Microsoft.Web/sites/MagooBlazor 10 | Default-Web-NorthEurope 11 | AzureWebSite 12 | Release 13 | Any CPU 14 | https://magooblazor.azurewebsites.net 15 | True 16 | False 17 | netstandard2.0 18 | a2454d7f-581c-4784-adc0-ba3f227ac66e 19 | magooblazor.scm.azurewebsites.net:443 20 | MagooBlazor 21 | 22 | False 23 | WMSVC 24 | True 25 | $MagooBlazor 26 | <_SavePWD>True 27 | <_DestinationType>AzureWebSite 28 | False 29 | 30 | -------------------------------------------------------------------------------- /BlazorBinding/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:59580/", 7 | "sslPort": 59581 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "BlazorBinding": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "environmentVariables": { 22 | "ASPNETCORE_ENVIRONMENT": "Development" 23 | }, 24 | "applicationUrl": "http://localhost:59580" 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /BlazorBinding/Services/CodeHighlighter.cs: -------------------------------------------------------------------------------- 1 |  2 | using ColorCode; 3 | using ColorCode.Common; 4 | using ColorCode.Styling; 5 | 6 | namespace BlazorBinding.Services 7 | { 8 | public class CodeHighlighter : ICodeHighlighter 9 | { 10 | public HtmlFormatter Formatter { get; } 11 | 12 | public CodeHighlighter() 13 | { 14 | StyleDictionary style = StyleDictionary.DefaultLight; 15 | style[ScopeName.PlainText].Background = ""; 16 | Formatter = new HtmlFormatter(style); 17 | } 18 | 19 | public string HighlightHtml(string HtmlString) 20 | { 21 | return HighlightCode("Html", HtmlString); 22 | } 23 | 24 | public string HighlightCSharp(string CSharpString) 25 | { 26 | return HighlightCode("CSharp", CSharpString); 27 | } 28 | 29 | private string HighlightCode(string Language, string code) 30 | { 31 | var lang = ColorCode.Languages.FindById(Language); 32 | if (lang == null) 33 | { 34 | var langName = System.Net.WebUtility.HtmlEncode(Language); 35 | return $"Unable to parse language {langName}"; 36 | } 37 | return Formatter.GetHtmlString(code, lang); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /BlazorBinding/Services/ICodeHighlighter.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace BlazorBinding.Services 3 | { 4 | public interface ICodeHighlighter 5 | { 6 | string HighlightHtml(string HtmlString); 7 | 8 | string HighlightCSharp(string CSharpString); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /BlazorBinding/Shared/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @inherits LayoutComponentBase 2 | @using BlazorBinding.Components 3 | 6 | 7 |
8 |
9 | Blazor.Net 10 |
11 | 12 |
13 | 14 | @Body 15 | 16 |
17 |
18 | 19 | 20 | 21 | 22 | @functions 23 | { 24 | public MMDialog MMDialogRef { get; private set; } 25 | 26 | protected override void OnAfterRender(bool firstRender) 27 | { 28 | if (MMDialogRef == null) 29 | { 30 | Console.WriteLine($"No REF"); 31 | } 32 | else 33 | { 34 | Console.WriteLine($"TYPE: {MMDialogRef.GetType().Name}"); 35 | } 36 | } 37 | 38 | // 39 | } -------------------------------------------------------------------------------- /BlazorBinding/Shared/NavMenu.razor: -------------------------------------------------------------------------------- 1 |  2 | 8 | 9 |
10 | 82 |
83 | 84 | @functions { 85 | bool collapseNavMenu = true; 86 | 87 | void ToggleNavMenu() 88 | { 89 | collapseNavMenu = !collapseNavMenu; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /BlazorBinding/Startup.cs: -------------------------------------------------------------------------------- 1 | using BlazorBinding.Services; 2 | using Microsoft.AspNetCore.Components.Builder; 3 | using Microsoft.Extensions.DependencyInjection; 4 | 5 | namespace BlazorBinding 6 | { 7 | public class Startup 8 | { 9 | public void ConfigureServices(IServiceCollection services) 10 | { 11 | services.AddSingleton((sp) => new CodeHighlighter()); 12 | } 13 | 14 | public void Configure(IComponentsApplicationBuilder app) 15 | { 16 | app.AddComponent("app"); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /BlazorBinding/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using Microsoft.AspNetCore.Components.Forms 3 | @using Microsoft.AspNetCore.Components.Routing 4 | @using Microsoft.AspNetCore.Components.Web 5 | @using Microsoft.JSInterop 6 | @using BlazorBinding 7 | @using BlazorBinding.Shared 8 | @using BlazorBinding.Components 9 | @using BlazorBinding.Components.DocumentationSupport -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | #ffffff -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/css/open-iconic/FONT-LICENSE: -------------------------------------------------------------------------------- 1 | SIL OPEN FONT LICENSE Version 1.1 2 | 3 | Copyright (c) 2014 Waybury 4 | 5 | PREAMBLE 6 | The goals of the Open Font License (OFL) are to stimulate worldwide 7 | development of collaborative font projects, to support the font creation 8 | efforts of academic and linguistic communities, and to provide a free and 9 | open framework in which fonts may be shared and improved in partnership 10 | with others. 11 | 12 | The OFL allows the licensed fonts to be used, studied, modified and 13 | redistributed freely as long as they are not sold by themselves. The 14 | fonts, including any derivative works, can be bundled, embedded, 15 | redistributed and/or sold with any software provided that any reserved 16 | names are not used by derivative works. The fonts and derivatives, 17 | however, cannot be released under any other type of license. The 18 | requirement for fonts to remain under this license does not apply 19 | to any document created using the fonts or their derivatives. 20 | 21 | DEFINITIONS 22 | "Font Software" refers to the set of files released by the Copyright 23 | Holder(s) under this license and clearly marked as such. This may 24 | include source files, build scripts and documentation. 25 | 26 | "Reserved Font Name" refers to any names specified as such after the 27 | copyright statement(s). 28 | 29 | "Original Version" refers to the collection of Font Software components as 30 | distributed by the Copyright Holder(s). 31 | 32 | "Modified Version" refers to any derivative made by adding to, deleting, 33 | or substituting -- in part or in whole -- any of the components of the 34 | Original Version, by changing formats or by porting the Font Software to a 35 | new environment. 36 | 37 | "Author" refers to any designer, engineer, programmer, technical 38 | writer or other person who contributed to the Font Software. 39 | 40 | PERMISSION & CONDITIONS 41 | Permission is hereby granted, free of charge, to any person obtaining 42 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 43 | redistribute, and sell modified and unmodified copies of the Font 44 | Software, subject to the following conditions: 45 | 46 | 1) Neither the Font Software nor any of its individual components, 47 | in Original or Modified Versions, may be sold by itself. 48 | 49 | 2) Original or Modified Versions of the Font Software may be bundled, 50 | redistributed and/or sold with any software, provided that each copy 51 | contains the above copyright notice and this license. These can be 52 | included either as stand-alone text files, human-readable headers or 53 | in the appropriate machine-readable metadata fields within text or 54 | binary files as long as those fields can be easily viewed by the user. 55 | 56 | 3) No Modified Version of the Font Software may use the Reserved Font 57 | Name(s) unless explicit written permission is granted by the corresponding 58 | Copyright Holder. This restriction only applies to the primary font name as 59 | presented to the users. 60 | 61 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 62 | Software shall not be used to promote, endorse or advertise any 63 | Modified Version, except to acknowledge the contribution(s) of the 64 | Copyright Holder(s) and the Author(s) or with their explicit written 65 | permission. 66 | 67 | 5) The Font Software, modified or unmodified, in part or in whole, 68 | must be distributed entirely under this license, and must not be 69 | distributed under any other license. The requirement for fonts to 70 | remain under this license does not apply to any document created 71 | using the Font Software. 72 | 73 | TERMINATION 74 | This license becomes null and void if any of the above conditions are 75 | not met. 76 | 77 | DISCLAIMER 78 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 79 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 80 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 81 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 82 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 83 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 84 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 85 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 86 | OTHER DEALINGS IN THE FONT SOFTWARE. 87 | -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/css/open-iconic/ICON-LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Waybury 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/css/open-iconic/README.md: -------------------------------------------------------------------------------- 1 | [Open Iconic v1.1.1](http://useiconic.com/open) 2 | =========== 3 | 4 | ### Open Iconic is the open source sibling of [Iconic](http://useiconic.com). It is a hyper-legible collection of 223 icons with a tiny footprint—ready to use with Bootstrap and Foundation. [View the collection](http://useiconic.com/open#icons) 5 | 6 | 7 | 8 | ## What's in Open Iconic? 9 | 10 | * 223 icons designed to be legible down to 8 pixels 11 | * Super-light SVG files - 61.8 for the entire set 12 | * SVG sprite—the modern replacement for icon fonts 13 | * Webfont (EOT, OTF, SVG, TTF, WOFF), PNG and WebP formats 14 | * Webfont stylesheets (including versions for Bootstrap and Foundation) in CSS, LESS, SCSS and Stylus formats 15 | * PNG and WebP raster images in 8px, 16px, 24px, 32px, 48px and 64px. 16 | 17 | 18 | ## Getting Started 19 | 20 | #### For code samples and everything else you need to get started with Open Iconic, check out our [Icons](http://useiconic.com/open#icons) and [Reference](http://useiconic.com/open#reference) sections. 21 | 22 | ### General Usage 23 | 24 | #### Using Open Iconic's SVGs 25 | 26 | We like SVGs and we think they're the way to display icons on the web. Since Open Iconic are just basic SVGs, we suggest you display them like you would any other image (don't forget the `alt` attribute). 27 | 28 | ``` 29 | icon name 30 | ``` 31 | 32 | #### Using Open Iconic's SVG Sprite 33 | 34 | Open Iconic also comes in a SVG sprite which allows you to display all the icons in the set with a single request. It's like an icon font, without being a hack. 35 | 36 | Adding an icon from an SVG sprite is a little different than what you're used to, but it's still a piece of cake. *Tip: To make your icons easily style able, we suggest adding a general class to the* `` *tag and a unique class name for each different icon in the* `` *tag.* 37 | 38 | ``` 39 | 40 | 41 | 42 | ``` 43 | 44 | Sizing icons only needs basic CSS. All the icons are in a square format, so just set the `` tag with equal width and height dimensions. 45 | 46 | ``` 47 | .icon { 48 | width: 16px; 49 | height: 16px; 50 | } 51 | ``` 52 | 53 | Coloring icons is even easier. All you need to do is set the `fill` rule on the `` tag. 54 | 55 | ``` 56 | .icon-account-login { 57 | fill: #f00; 58 | } 59 | ``` 60 | 61 | To learn more about SVG Sprites, read [Chris Coyier's guide](http://css-tricks.com/svg-sprites-use-better-icon-fonts/). 62 | 63 | #### Using Open Iconic's Icon Font... 64 | 65 | 66 | ##### …with Bootstrap 67 | 68 | You can find our Bootstrap stylesheets in `font/css/open-iconic-bootstrap.{css, less, scss, styl}` 69 | 70 | 71 | ``` 72 | 73 | ``` 74 | 75 | 76 | ``` 77 | 78 | ``` 79 | 80 | ##### …with Foundation 81 | 82 | You can find our Foundation stylesheets in `font/css/open-iconic-foundation.{css, less, scss, styl}` 83 | 84 | ``` 85 | 86 | ``` 87 | 88 | 89 | ``` 90 | 91 | ``` 92 | 93 | ##### …on its own 94 | 95 | You can find our default stylesheets in `font/css/open-iconic.{css, less, scss, styl}` 96 | 97 | ``` 98 | 99 | ``` 100 | 101 | ``` 102 | 103 | ``` 104 | 105 | 106 | ## License 107 | 108 | ### Icons 109 | 110 | All code (including SVG markup) is under the [MIT License](http://opensource.org/licenses/MIT). 111 | 112 | ### Fonts 113 | 114 | All fonts are under the [SIL Licensed](http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web). 115 | -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css: -------------------------------------------------------------------------------- 1 | @font-face{font-family:Icons;src:url(../fonts/open-iconic.eot);src:url(../fonts/open-iconic.eot?#iconic-sm) format('embedded-opentype'),url(../fonts/open-iconic.woff) format('woff'),url(../fonts/open-iconic.ttf) format('truetype'),url(../fonts/open-iconic.otf) format('opentype'),url(../fonts/open-iconic.svg#iconic-sm) format('svg');font-weight:400;font-style:normal}.oi{position:relative;top:1px;display:inline-block;speak:none;font-family:Icons;font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.oi:empty:before{width:1em;text-align:center;box-sizing:content-box}.oi.oi-align-center:before{text-align:center}.oi.oi-align-left:before{text-align:left}.oi.oi-align-right:before{text-align:right}.oi.oi-flip-horizontal:before{-webkit-transform:scale(-1,1);-ms-transform:scale(-1,1);transform:scale(-1,1)}.oi.oi-flip-vertical:before{-webkit-transform:scale(1,-1);-ms-transform:scale(-1,1);transform:scale(1,-1)}.oi.oi-flip-horizontal-vertical:before{-webkit-transform:scale(-1,-1);-ms-transform:scale(-1,1);transform:scale(-1,-1)}.oi-account-login:before{content:'\e000'}.oi-account-logout:before{content:'\e001'}.oi-action-redo:before{content:'\e002'}.oi-action-undo:before{content:'\e003'}.oi-align-center:before{content:'\e004'}.oi-align-left:before{content:'\e005'}.oi-align-right:before{content:'\e006'}.oi-aperture:before{content:'\e007'}.oi-arrow-bottom:before{content:'\e008'}.oi-arrow-circle-bottom:before{content:'\e009'}.oi-arrow-circle-left:before{content:'\e00a'}.oi-arrow-circle-right:before{content:'\e00b'}.oi-arrow-circle-top:before{content:'\e00c'}.oi-arrow-left:before{content:'\e00d'}.oi-arrow-right:before{content:'\e00e'}.oi-arrow-thick-bottom:before{content:'\e00f'}.oi-arrow-thick-left:before{content:'\e010'}.oi-arrow-thick-right:before{content:'\e011'}.oi-arrow-thick-top:before{content:'\e012'}.oi-arrow-top:before{content:'\e013'}.oi-audio-spectrum:before{content:'\e014'}.oi-audio:before{content:'\e015'}.oi-badge:before{content:'\e016'}.oi-ban:before{content:'\e017'}.oi-bar-chart:before{content:'\e018'}.oi-basket:before{content:'\e019'}.oi-battery-empty:before{content:'\e01a'}.oi-battery-full:before{content:'\e01b'}.oi-beaker:before{content:'\e01c'}.oi-bell:before{content:'\e01d'}.oi-bluetooth:before{content:'\e01e'}.oi-bold:before{content:'\e01f'}.oi-bolt:before{content:'\e020'}.oi-book:before{content:'\e021'}.oi-bookmark:before{content:'\e022'}.oi-box:before{content:'\e023'}.oi-briefcase:before{content:'\e024'}.oi-british-pound:before{content:'\e025'}.oi-browser:before{content:'\e026'}.oi-brush:before{content:'\e027'}.oi-bug:before{content:'\e028'}.oi-bullhorn:before{content:'\e029'}.oi-calculator:before{content:'\e02a'}.oi-calendar:before{content:'\e02b'}.oi-camera-slr:before{content:'\e02c'}.oi-caret-bottom:before{content:'\e02d'}.oi-caret-left:before{content:'\e02e'}.oi-caret-right:before{content:'\e02f'}.oi-caret-top:before{content:'\e030'}.oi-cart:before{content:'\e031'}.oi-chat:before{content:'\e032'}.oi-check:before{content:'\e033'}.oi-chevron-bottom:before{content:'\e034'}.oi-chevron-left:before{content:'\e035'}.oi-chevron-right:before{content:'\e036'}.oi-chevron-top:before{content:'\e037'}.oi-circle-check:before{content:'\e038'}.oi-circle-x:before{content:'\e039'}.oi-clipboard:before{content:'\e03a'}.oi-clock:before{content:'\e03b'}.oi-cloud-download:before{content:'\e03c'}.oi-cloud-upload:before{content:'\e03d'}.oi-cloud:before{content:'\e03e'}.oi-cloudy:before{content:'\e03f'}.oi-code:before{content:'\e040'}.oi-cog:before{content:'\e041'}.oi-collapse-down:before{content:'\e042'}.oi-collapse-left:before{content:'\e043'}.oi-collapse-right:before{content:'\e044'}.oi-collapse-up:before{content:'\e045'}.oi-command:before{content:'\e046'}.oi-comment-square:before{content:'\e047'}.oi-compass:before{content:'\e048'}.oi-contrast:before{content:'\e049'}.oi-copywriting:before{content:'\e04a'}.oi-credit-card:before{content:'\e04b'}.oi-crop:before{content:'\e04c'}.oi-dashboard:before{content:'\e04d'}.oi-data-transfer-download:before{content:'\e04e'}.oi-data-transfer-upload:before{content:'\e04f'}.oi-delete:before{content:'\e050'}.oi-dial:before{content:'\e051'}.oi-document:before{content:'\e052'}.oi-dollar:before{content:'\e053'}.oi-double-quote-sans-left:before{content:'\e054'}.oi-double-quote-sans-right:before{content:'\e055'}.oi-double-quote-serif-left:before{content:'\e056'}.oi-double-quote-serif-right:before{content:'\e057'}.oi-droplet:before{content:'\e058'}.oi-eject:before{content:'\e059'}.oi-elevator:before{content:'\e05a'}.oi-ellipses:before{content:'\e05b'}.oi-envelope-closed:before{content:'\e05c'}.oi-envelope-open:before{content:'\e05d'}.oi-euro:before{content:'\e05e'}.oi-excerpt:before{content:'\e05f'}.oi-expand-down:before{content:'\e060'}.oi-expand-left:before{content:'\e061'}.oi-expand-right:before{content:'\e062'}.oi-expand-up:before{content:'\e063'}.oi-external-link:before{content:'\e064'}.oi-eye:before{content:'\e065'}.oi-eyedropper:before{content:'\e066'}.oi-file:before{content:'\e067'}.oi-fire:before{content:'\e068'}.oi-flag:before{content:'\e069'}.oi-flash:before{content:'\e06a'}.oi-folder:before{content:'\e06b'}.oi-fork:before{content:'\e06c'}.oi-fullscreen-enter:before{content:'\e06d'}.oi-fullscreen-exit:before{content:'\e06e'}.oi-globe:before{content:'\e06f'}.oi-graph:before{content:'\e070'}.oi-grid-four-up:before{content:'\e071'}.oi-grid-three-up:before{content:'\e072'}.oi-grid-two-up:before{content:'\e073'}.oi-hard-drive:before{content:'\e074'}.oi-header:before{content:'\e075'}.oi-headphones:before{content:'\e076'}.oi-heart:before{content:'\e077'}.oi-home:before{content:'\e078'}.oi-image:before{content:'\e079'}.oi-inbox:before{content:'\e07a'}.oi-infinity:before{content:'\e07b'}.oi-info:before{content:'\e07c'}.oi-italic:before{content:'\e07d'}.oi-justify-center:before{content:'\e07e'}.oi-justify-left:before{content:'\e07f'}.oi-justify-right:before{content:'\e080'}.oi-key:before{content:'\e081'}.oi-laptop:before{content:'\e082'}.oi-layers:before{content:'\e083'}.oi-lightbulb:before{content:'\e084'}.oi-link-broken:before{content:'\e085'}.oi-link-intact:before{content:'\e086'}.oi-list-rich:before{content:'\e087'}.oi-list:before{content:'\e088'}.oi-location:before{content:'\e089'}.oi-lock-locked:before{content:'\e08a'}.oi-lock-unlocked:before{content:'\e08b'}.oi-loop-circular:before{content:'\e08c'}.oi-loop-square:before{content:'\e08d'}.oi-loop:before{content:'\e08e'}.oi-magnifying-glass:before{content:'\e08f'}.oi-map-marker:before{content:'\e090'}.oi-map:before{content:'\e091'}.oi-media-pause:before{content:'\e092'}.oi-media-play:before{content:'\e093'}.oi-media-record:before{content:'\e094'}.oi-media-skip-backward:before{content:'\e095'}.oi-media-skip-forward:before{content:'\e096'}.oi-media-step-backward:before{content:'\e097'}.oi-media-step-forward:before{content:'\e098'}.oi-media-stop:before{content:'\e099'}.oi-medical-cross:before{content:'\e09a'}.oi-menu:before{content:'\e09b'}.oi-microphone:before{content:'\e09c'}.oi-minus:before{content:'\e09d'}.oi-monitor:before{content:'\e09e'}.oi-moon:before{content:'\e09f'}.oi-move:before{content:'\e0a0'}.oi-musical-note:before{content:'\e0a1'}.oi-paperclip:before{content:'\e0a2'}.oi-pencil:before{content:'\e0a3'}.oi-people:before{content:'\e0a4'}.oi-person:before{content:'\e0a5'}.oi-phone:before{content:'\e0a6'}.oi-pie-chart:before{content:'\e0a7'}.oi-pin:before{content:'\e0a8'}.oi-play-circle:before{content:'\e0a9'}.oi-plus:before{content:'\e0aa'}.oi-power-standby:before{content:'\e0ab'}.oi-print:before{content:'\e0ac'}.oi-project:before{content:'\e0ad'}.oi-pulse:before{content:'\e0ae'}.oi-puzzle-piece:before{content:'\e0af'}.oi-question-mark:before{content:'\e0b0'}.oi-rain:before{content:'\e0b1'}.oi-random:before{content:'\e0b2'}.oi-reload:before{content:'\e0b3'}.oi-resize-both:before{content:'\e0b4'}.oi-resize-height:before{content:'\e0b5'}.oi-resize-width:before{content:'\e0b6'}.oi-rss-alt:before{content:'\e0b7'}.oi-rss:before{content:'\e0b8'}.oi-script:before{content:'\e0b9'}.oi-share-boxed:before{content:'\e0ba'}.oi-share:before{content:'\e0bb'}.oi-shield:before{content:'\e0bc'}.oi-signal:before{content:'\e0bd'}.oi-signpost:before{content:'\e0be'}.oi-sort-ascending:before{content:'\e0bf'}.oi-sort-descending:before{content:'\e0c0'}.oi-spreadsheet:before{content:'\e0c1'}.oi-star:before{content:'\e0c2'}.oi-sun:before{content:'\e0c3'}.oi-tablet:before{content:'\e0c4'}.oi-tag:before{content:'\e0c5'}.oi-tags:before{content:'\e0c6'}.oi-target:before{content:'\e0c7'}.oi-task:before{content:'\e0c8'}.oi-terminal:before{content:'\e0c9'}.oi-text:before{content:'\e0ca'}.oi-thumb-down:before{content:'\e0cb'}.oi-thumb-up:before{content:'\e0cc'}.oi-timer:before{content:'\e0cd'}.oi-transfer:before{content:'\e0ce'}.oi-trash:before{content:'\e0cf'}.oi-underline:before{content:'\e0d0'}.oi-vertical-align-bottom:before{content:'\e0d1'}.oi-vertical-align-center:before{content:'\e0d2'}.oi-vertical-align-top:before{content:'\e0d3'}.oi-video:before{content:'\e0d4'}.oi-volume-high:before{content:'\e0d5'}.oi-volume-low:before{content:'\e0d6'}.oi-volume-off:before{content:'\e0d7'}.oi-warning:before{content:'\e0d8'}.oi-wifi:before{content:'\e0d9'}.oi-wrench:before{content:'\e0da'}.oi-x:before{content:'\e0db'}.oi-yen:before{content:'\e0dc'}.oi-zoom-in:before{content:'\e0dd'}.oi-zoom-out:before{content:'\e0de'} -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/css/open-iconic/font/fonts/open-iconic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/css/open-iconic/font/fonts/open-iconic.eot -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/css/open-iconic/font/fonts/open-iconic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/css/open-iconic/font/fonts/open-iconic.otf -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/css/open-iconic/font/fonts/open-iconic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Created by FontForge 20120731 at Tue Jul 1 20:39:22 2014 9 | By P.J. Onori 10 | Created by P.J. Onori with FontForge 2.0 (http://fontforge.sf.net) 11 | 12 | 13 | 14 | 27 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | 42 | 45 | 47 | 49 | 51 | 53 | 55 | 57 | 59 | 61 | 63 | 65 | 67 | 69 | 71 | 74 | 76 | 79 | 81 | 84 | 86 | 88 | 91 | 93 | 95 | 98 | 100 | 102 | 104 | 106 | 109 | 112 | 115 | 117 | 121 | 123 | 125 | 127 | 130 | 132 | 134 | 136 | 138 | 141 | 143 | 145 | 147 | 149 | 151 | 153 | 155 | 157 | 159 | 162 | 165 | 167 | 169 | 172 | 174 | 177 | 179 | 181 | 183 | 185 | 189 | 191 | 194 | 196 | 198 | 200 | 202 | 205 | 207 | 209 | 211 | 213 | 215 | 218 | 220 | 222 | 224 | 226 | 228 | 230 | 232 | 234 | 236 | 238 | 241 | 243 | 245 | 247 | 249 | 251 | 253 | 256 | 259 | 261 | 263 | 265 | 267 | 269 | 272 | 274 | 276 | 280 | 282 | 285 | 287 | 289 | 292 | 295 | 298 | 300 | 302 | 304 | 306 | 309 | 312 | 314 | 316 | 318 | 320 | 322 | 324 | 326 | 330 | 334 | 338 | 340 | 343 | 345 | 347 | 349 | 351 | 353 | 355 | 358 | 360 | 363 | 365 | 367 | 369 | 371 | 373 | 375 | 377 | 379 | 381 | 383 | 386 | 388 | 390 | 392 | 394 | 396 | 399 | 401 | 404 | 406 | 408 | 410 | 412 | 414 | 416 | 419 | 421 | 423 | 425 | 428 | 431 | 435 | 438 | 440 | 442 | 444 | 446 | 448 | 451 | 453 | 455 | 457 | 460 | 462 | 464 | 466 | 468 | 471 | 473 | 477 | 479 | 481 | 483 | 486 | 488 | 490 | 492 | 494 | 496 | 499 | 501 | 504 | 506 | 509 | 512 | 515 | 517 | 520 | 522 | 524 | 526 | 529 | 532 | 534 | 536 | 539 | 542 | 543 | 544 | -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/css/open-iconic/font/fonts/open-iconic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/css/open-iconic/font/fonts/open-iconic.woff -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | @import url('open-iconic/font/css/open-iconic-bootstrap.min.css'); 2 | 3 | html, body { 4 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 5 | width: 100vw; 6 | height: 100vh; 7 | } 8 | 9 | app { 10 | position: relative; 11 | display: flex; 12 | flex-direction: column; 13 | --app-animation: LOADED; 14 | } 15 | 16 | app:not(:empty)::after { 17 | content: ""; 18 | animation: var(--app-animation) 1s ease-in; 19 | } 20 | 21 | app:empty { 22 | display: grid; 23 | height: 100vh; 24 | width: 100vw; 25 | font-size: xx-large; 26 | grid-template-columns: 100vw; 27 | grid-template-rows: 100vh; 28 | line-height: 100vh; 29 | text-align: center; 30 | vertical-align: middle; 31 | background-color: var(--gray); 32 | color: var(--white); 33 | } 34 | 35 | app:empty::before { 36 | content: "Loading WebAssembly"; 37 | grid-row: 1; 38 | grid-column: 1; 39 | animation: LOADING 1s infinite alternate; 40 | } 41 | 42 | .top-row { 43 | height: 3.5rem; 44 | display: flex; 45 | align-items: center; 46 | } 47 | 48 | .main { 49 | flex: 1; 50 | } 51 | 52 | .main .top-row { 53 | background-color: #e6e6e6; 54 | border-bottom: 1px solid #d6d5d5; 55 | } 56 | 57 | .sidebar { 58 | background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); 59 | } 60 | 61 | .sidebar .top-row { 62 | background-color: rgba(0,0,0,0.4); 63 | } 64 | 65 | .sidebar .navbar-brand { 66 | font-size: 1.1rem; 67 | } 68 | 69 | .sidebar .oi { 70 | width: 2rem; 71 | font-size: 1.1rem; 72 | vertical-align: text-top; 73 | top: -2px; 74 | } 75 | 76 | .nav-item { 77 | font-size: 0.9rem; 78 | padding-bottom: 0.5rem; 79 | } 80 | 81 | .nav-item:first-of-type { 82 | padding-top: 1rem; 83 | } 84 | 85 | .nav-item:last-of-type { 86 | padding-bottom: 1rem; 87 | } 88 | 89 | .nav-item a { 90 | color: #d7d7d7; 91 | border-radius: 4px; 92 | height: 3rem; 93 | display: flex; 94 | align-items: center; 95 | line-height: 3rem; 96 | } 97 | 98 | .nav-item a.active { 99 | background-color: rgba(255,255,255,0.25); 100 | color: white; 101 | } 102 | 103 | .nav-item a:hover { 104 | background-color: rgba(255,255,255,0.1); 105 | color: white; 106 | } 107 | 108 | .content { 109 | padding-top: 1.1rem; 110 | } 111 | 112 | .navbar-toggler { 113 | background-color: rgba(255, 255, 255, 0.1); 114 | } 115 | 116 | /* Docs */ 117 | .card { 118 | margin-bottom: 5px; 119 | } 120 | 121 | .card input[type=checkbox]:not(.form-check-input) { 122 | width: 1.5em; 123 | height: 1.5em; 124 | vertical-align: middle; 125 | } 126 | 127 | .code-highlight { 128 | overflow: auto; 129 | background: rgba(2,2,2,0.1); 130 | color: #000; 131 | padding: 5px 5px; 132 | border-left: 20px solid rgba(2,2,2,0.3); 133 | } 134 | 135 | .code-highlight pre { 136 | color: #000; 137 | margin: 0; 138 | } 139 | 140 | .callout-parent { 141 | border-left: 5px solid #17a2b8; 142 | padding-left: 5px; 143 | } 144 | 145 | .callout-child { 146 | border-left: 5px solid #ffc107; 147 | padding-left: 5px; 148 | } 149 | 150 | .ping-on { 151 | -webkit-animation-name: ping; /* Safari 4.0 - 8.0 */ 152 | -webkit-animation-duration: 1s; /* Safari 4.0 - 8.0 */ 153 | animation-name: ping; 154 | animation-duration: 1s; 155 | } 156 | 157 | .ping-off { 158 | -webkit-animation-name: ping-off; /* Safari 4.0 - 8.0 */ 159 | -webkit-animation-duration: 1s; /* Safari 4.0 - 8.0 */ 160 | animation-name: ping-off; 161 | animation-duration: 1s; 162 | } 163 | 164 | span[class^="ping-date-"] { 165 | -webkit-animation-name: ping-off; /* Safari 4.0 - 8.0 */ 166 | -webkit-animation-duration: 1s; /* Safari 4.0 - 8.0 */ 167 | animation-name: ping-off; 168 | animation-duration: 1s; 169 | } 170 | /* Safari 4.0 - 8.0 */ 171 | @-webkit-keyframes ping { 172 | 0% { 173 | background-color: white; 174 | } 175 | 176 | 25% { 177 | background-color: yellow; 178 | } 179 | 180 | 50% { 181 | background-color: yellow; 182 | } 183 | 184 | 100% { 185 | background-color: white; 186 | } 187 | } 188 | /* Standard syntax */ 189 | @keyframes ping { 190 | 0% { 191 | background-color: white; 192 | } 193 | 194 | 25% { 195 | background-color: yellow; 196 | } 197 | 198 | 50% { 199 | background-color: yellow; 200 | } 201 | 202 | 100% { 203 | background-color: white; 204 | } 205 | } 206 | 207 | @-webkit-keyframes ping-off { 208 | 0% { 209 | background-color: white; 210 | } 211 | 212 | 25% { 213 | background-color: yellow; 214 | } 215 | 216 | 50% { 217 | background-color: yellow; 218 | } 219 | 220 | 100% { 221 | background-color: white; 222 | } 223 | } 224 | /* Standard syntax */ 225 | @keyframes ping-off { 226 | 0% { 227 | background-color: white; 228 | } 229 | 230 | 25% { 231 | background-color: yellow; 232 | } 233 | 234 | 50% { 235 | background-color: yellow; 236 | } 237 | 238 | 100% { 239 | background-color: white; 240 | } 241 | } 242 | 243 | @media (max-width: 767.98px) { 244 | .main .top-row { 245 | display: none; 246 | } 247 | } 248 | 249 | @media (min-width: 768px) { 250 | app { 251 | flex-direction: row; 252 | } 253 | 254 | .sidebar { 255 | min-width: 330px; 256 | height: 100vh; 257 | position: sticky; 258 | top: 0; 259 | } 260 | 261 | .main .top-row { 262 | position: sticky; 263 | top: 0; 264 | } 265 | 266 | .main > div { 267 | padding-left: 2rem !important; 268 | padding-right: 1.5rem !important; 269 | } 270 | 271 | .navbar-toggler { 272 | display: none; 273 | } 274 | 275 | .sidebar .collapse { 276 | /* Never collapse the sidebar for wide screens */ 277 | display: block; 278 | } 279 | } 280 | 281 | @keyframes LOADING { 282 | 0% { 283 | content: "Loading WebAssembly"; 284 | } 285 | 286 | 20% { 287 | content: ".Loading WebAssembly."; 288 | } 289 | 290 | 40% { 291 | content: "..Loading WebAssembly.."; 292 | } 293 | 294 | 60% { 295 | content: "...Loading WebAssembly..."; 296 | } 297 | 298 | 80% { 299 | content: "....Loading WebAssembly...."; 300 | } 301 | 302 | 100% { 303 | content: ".....Loading WebAssembly....."; 304 | } 305 | } 306 | 307 | @keyframes LOADED { 308 | 0% { 309 | position: absolute; 310 | width: 100vw; 311 | height: 100vh; 312 | z-index: 900; 313 | background-color: var(--gray); 314 | opacity: 1; 315 | } 316 | 317 | 100% { 318 | position: absolute; 319 | width: 100vw; 320 | height: 100vh; 321 | z-index: -1; 322 | background-color: var(--gray); 323 | opacity: 0; 324 | } 325 | } 326 | -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/data/README.md: -------------------------------------------------------------------------------- 1 | # BlazorBinding 2 | Sample Blazor App demonstrating various data binding scenarios 3 | 4 | ## Simple Cascade 5 | Demonstrates how CascadingValue is a one-way data transfer, which updates the subscriber but not the publisher. 6 | 7 | ## Cascade With Callback 8 | Demonstrates how you can add a Callback Action to update the CascadingValue from subscriber to publisher. 9 | 10 | ## Simple Binding 11 | Demonstrates the use of parameter binding, which is a one-way binding like the CascadingValue, but specific to the bound Component. 12 | 13 | ## Simple Binding With Callback 14 | Demonstrates how you can add a Callback Action to update the parent values from the child. 15 | 16 | ## Value Binding 17 | Demonstrates how the bind-Value syntax works in a one-way mode, like simple binding. 18 | *This is considered to be a bug by many* 19 | 20 | ## Value Binding With Callback 21 | Demonstrates how you can update the parent from a child component by invoking the _required_ ValueChanged Action. 22 | 23 | ## Value Binding With Callback + Refresh 24 | Demonstrates how you can ensure the parent knows a child component has updated data, and trigger a refresh. 25 | 26 | ## Value Binding Class Object 27 | Demonstrates how to two-way bind a list of objects with multiple properties. 28 | 29 | ## The Problem With Clicks - "Propagation" 30 | Demonstrates how events on standard html elements propagate in Blazor. This is very bad. 31 | 32 | ## Using CascadingValue To Share A Global Component - Dialog 33 | Demonstrates how to use CascadingValue to share a component from MainLayout so that it is globally accessible. 34 | 35 | ## Autocomplete text input 36 | Demonstrates how to perform autocomplete on a text input. 37 | 38 | ## ViewModel Binding 39 | Demonstrates a simple method to enable a page to bind a ViewModel that automatically hooks into StateHasChanged. 40 | 41 | ### Summary 42 | 43 | In all cases, some kind of callback action is required to notify the parent component of a change in the data. 44 | This is, in my opinion OK - as it gives me control of the data and UI - however, some people consider the manual intervention required to be a bug. 45 | 46 | I have not included any examples of using "State" to achieve two way binding, although that is also possible, it would also require some kind of callback notification. 47 | -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/data/changelog.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "dated": "2019-07-26", 4 | "content": "Update to Asp.Net Core 3 Preview 7" 5 | }, 6 | { 7 | "dated": "2019-07-23", 8 | "content": "Update to Asp.Net Core 3 Preview 6", 9 | "child": [ 10 | { "text": "Many thanks to Howard Richards for the majority of the work in updating to preview 6" } 11 | ] 12 | }, 13 | { 14 | "dated": "2019-01-05", 15 | "content": "Add ViewModel Binding", 16 | "child": [ 17 | { "text": "Added BlazorComponentExt as the default component base class" }, 18 | { "text": "This enables the use of the new ModelAttribute," }, 19 | { "text": "Which auto hooks up StateHasChanged() to IPropertyNotifyChanged events." }, 20 | { "text": "Moved all @using statements to the base _ViewImports.cshtml to make it easier to add new pages." }, 21 | { "text": "Tidied up some of the page layouts."} 22 | ] 23 | }, 24 | { 25 | "dated": "2019-01-03", 26 | "content": "Add Autocomplete text input sample", 27 | "child": [ 28 | { "text": "This demonstrates how to perform autocomplete on a text input." } 29 | ] 30 | }, 31 | 32 | { 33 | "dated": "2018-12-21", 34 | "content": "Add Value Binding Class Object sample", 35 | "child": [ 36 | { "text": "This demonstrates how to two-way bind a list of objects with multiple properties" } 37 | ] 38 | }, 39 | { 40 | "dated": "2018-12-15", 41 | "content": "Add dialog button callbacks to the global dialog sample" 42 | }, 43 | { 44 | "dated": "2018-12-14", 45 | "content": "Add global dialog sample" 46 | }, 47 | { 48 | "dated": "2018-12-09", 49 | "content": "Migrate to Razor Components/Blazor 0.8.0-preview1-20181122.3" 50 | }, 51 | { 52 | "dated": "2018-12-06", 53 | "content": "Add page showing the problem with click propagation" 54 | }, 55 | { 56 | "dated": "2018-12-05", 57 | "content": "Style update from Howard Richards, including the ColorCode reference." 58 | }, 59 | { 60 | "dated": "2018-12-05", 61 | "content": "Now using a new DisplayCode component that is simpler and highlights syntax" 62 | }, 63 | { 64 | "dated": "2018-11-27", 65 | "content": "Style update from Ed Charbeneau, including these cards", 66 | "child": [ 67 | { "text": "Watch Ed's show #StateHasChanged on Twitch" }, 68 | { "text": "#StateHasChanged" } 69 | ] 70 | } 71 | ] 72 | -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/android-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/android-icon-144x144.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/android-icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/android-icon-192x192.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/android-icon-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/android-icon-36x36.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/android-icon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/android-icon-48x48.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/android-icon-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/android-icon-512x512.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/android-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/android-icon-72x72.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/android-icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/android-icon-96x96.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/apple-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/apple-icon-114x114.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/apple-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/apple-icon-120x120.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/apple-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/apple-icon-144x144.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/apple-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/apple-icon-152x152.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/apple-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/apple-icon-180x180.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/apple-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/apple-icon-57x57.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/apple-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/apple-icon-60x60.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/apple-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/apple-icon-72x72.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/apple-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/apple-icon-76x76.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/apple-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/apple-icon-precomposed.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/apple-icon.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/favicon-16x16.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/favicon-32x32.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/favicon-96x96.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/favicon.ico -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/ms-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/ms-icon-144x144.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/ms-icon-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/ms-icon-150x150.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/ms-icon-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/ms-icon-310x310.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/images/ms-icon-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQL-MisterMagoo/BlazorBinding/2cc269c12100c96cebb2599324b7b100280c0cef/BlazorBinding/wwwroot/images/ms-icon-70x70.png -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/index.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | BlazorBinding 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/js/Helpers.js: -------------------------------------------------------------------------------- 1 | window.helpers = { 2 | setProperty: function (el, prop, value) { 3 | try { 4 | document.querySelector(el).style.setProperty(prop, value); 5 | return true; 6 | } catch (e) { 7 | console.log(e); 8 | return false; 9 | } 10 | } 11 | }; -------------------------------------------------------------------------------- /BlazorBinding/wwwroot/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "App", 3 | "icons": [ 4 | { 5 | "src": "\/images\/android-icon-36x36.png", 6 | "sizes": "36x36", 7 | "type": "image\/png", 8 | "density": "0.75" 9 | }, 10 | { 11 | "src": "\/images\/android-icon-48x48.png", 12 | "sizes": "48x48", 13 | "type": "image\/png", 14 | "density": "1.0" 15 | }, 16 | { 17 | "src": "\/images\/android-icon-72x72.png", 18 | "sizes": "72x72", 19 | "type": "image\/png", 20 | "density": "1.5" 21 | }, 22 | { 23 | "src": "\/images\/android-icon-96x96.png", 24 | "sizes": "96x96", 25 | "type": "image\/png", 26 | "density": "2.0" 27 | }, 28 | { 29 | "src": "\/images\/android-icon-144x144.png", 30 | "sizes": "144x144", 31 | "type": "image\/png", 32 | "density": "3.0" 33 | }, 34 | { 35 | "src": "\/images\/android-icon-192x192.png", 36 | "sizes": "192x192", 37 | "type": "image\/png", 38 | "density": "4.0" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | [2.1.*,2.2.0) 4 | 3.1.0-preview4.19579.2 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BlazorBinding 2 | Sample Blazor App demonstrating various data binding scenarios 3 | 4 | ## Simple Cascade 5 | Demonstrates how CascadingValue is a one-way data transfer, which updates the subscriber but not the publisher. 6 | 7 | ## Cascade With Callback 8 | Demonstrates how you can add a Callback Action to update the CascadingValue from subscriber to publisher. 9 | 10 | ## Simple Binding 11 | Demonstrates the use of parameter binding, which is a one-way binding like the CascadingValue, but specific to the bound Component. 12 | 13 | ## Simple Binding With Callback 14 | Demonstrates how you can add a Callback Action to update the parent values from the child. 15 | 16 | ## Value Binding 17 | Demonstrates how the @bind-Value syntax works in a one-way mode, like simple binding. 18 | *This is considered to be a bug by many* 19 | 20 | ## Value Binding With Callback 21 | Demonstrates how you can update the parent from a child component by invoking the _required_ ValueChanged Action. 22 | 23 | ## Value Binding With Callback + Refresh 24 | Demonstrates how you can ensure the parent knows a child component has updated data, and trigger a refresh. 25 | 26 | ## Value Binding Class Object 27 | Demonstrates how to two-way bind a list of objects with multiple properties. 28 | 29 | ## The Problem With Clicks - "Propagation" 30 | Demonstrates how events on standard html elements propagate in Blazor. This is very bad. 31 | 32 | ## Using CascadingValue To Share A Global Component - Dialog 33 | Demonstrates how to use CascadingValue to share a component from MainLayout so that it is globally accessible. 34 | 35 | ## Autocomplete text input 36 | Demonstrates how to perform autocomplete on a text input. 37 | 38 | ## ViewModel Binding 39 | Demonstrates a simple method to enable a page to bind a ViewModel that automatically hooks into StateHasChanged. 40 | 41 | ### Summary 42 | 43 | In all cases, some kind of callback action is required to notify the parent component of a change in the data. 44 | This is, in my opinion OK - as it gives me control of the data and UI - however, some people consider the manual intervention required to be a bug. 45 | 46 | I have not included any examples of using "State" to achieve two way binding, although that is also possible, it would also require some kind of callback notification. 47 | --------------------------------------------------------------------------------