Skip to content

Commit 2095d51

Browse files
Merge pull request #5604 from MicrosoftDocs/copilot/fix-4609
Add example of mixing {x:Bind} and {Binding} in reusable Styles
2 parents 8361dd9 + 828fc06 commit 2095d51

File tree

2 files changed

+377
-0
lines changed

2 files changed

+377
-0
lines changed

hub/apps/develop/data-binding/data-binding-in-depth.md

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,197 @@ namespace ExampleNamespace
439439
</Window>
440440
```
441441

442+
### Mixing {x\:Bind} and {Binding} in a reusable Style
443+
444+
While the previous example showed using `{x:Bind}` in DataTemplates, you can also create reusable Styles that combine both `{x:Bind}` and `{Binding}` markup extensions. This is useful when you want to bind some properties to compile-time known values using `{x:Bind}` and other properties to runtime DataContext values using `{Binding}`.
445+
446+
Here's an example that shows how to create a reusable Button style that uses both binding approaches:
447+
448+
TemplatesResourceDictionary.xaml
449+
450+
``` xaml
451+
<!-- TemplatesResourceDictionary.xaml -->
452+
<ResourceDictionary
453+
x:Class="ExampleNamespace.TemplatesResourceDictionary"
454+
.....
455+
xmlns:examplenamespace="using:ExampleNamespace">
456+
457+
<!-- DataTemplate using x:Bind -->
458+
<DataTemplate x:Key="EmployeeTemplate" x:DataType="examplenamespace:IEmployee">
459+
<Grid>
460+
<TextBlock Text="{x:Bind Name}"/>
461+
</Grid>
462+
</DataTemplate>
463+
464+
<!-- Style that mixes x:Bind and Binding -->
465+
<Style x:Key="CustomButtonStyle" TargetType="Button">
466+
<Setter Property="Background" Value="{Binding ButtonBackgroundBrush}"/>
467+
<Setter Property="Foreground" Value="{Binding ButtonForegroundBrush}"/>
468+
<Setter Property="FontSize" Value="16"/>
469+
<Setter Property="Margin" Value="4"/>
470+
<Setter Property="Template">
471+
<Setter.Value>
472+
<ControlTemplate TargetType="Button">
473+
<Border x:Name="RootBorder"
474+
Background="{TemplateBinding Background}"
475+
BorderBrush="{TemplateBinding BorderBrush}"
476+
BorderThickness="{TemplateBinding BorderThickness}"
477+
CornerRadius="4">
478+
<StackPanel Orientation="Horizontal"
479+
HorizontalAlignment="Center"
480+
VerticalAlignment="Center">
481+
<!-- x:Bind to a static property or page-level property -->
482+
<Ellipse Width="8" Height="8"
483+
Fill="{x:Bind DefaultIndicatorBrush}"
484+
Margin="0,0,8,0"/>
485+
<!-- Binding to DataContext -->
486+
<ContentPresenter x:Name="ContentPresenter"
487+
Content="{TemplateBinding Content}"
488+
Foreground="{TemplateBinding Foreground}"
489+
FontSize="{TemplateBinding FontSize}"/>
490+
</StackPanel>
491+
<VisualStateManager.VisualStateGroups>
492+
<VisualStateGroup x:Name="CommonStates">
493+
<VisualState x:Name="Normal"/>
494+
<VisualState x:Name="PointerOver">
495+
<VisualState.Setters>
496+
<!-- Binding to DataContext for hover color -->
497+
<Setter Target="RootBorder.Background"
498+
Value="{Binding ButtonHoverBrush}"/>
499+
</VisualState.Setters>
500+
</VisualState>
501+
<VisualState x:Name="Pressed">
502+
<VisualState.Setters>
503+
<!-- x:Bind to a compile-time known resource -->
504+
<Setter Target="RootBorder.Background"
505+
Value="{x:Bind DefaultPressedBrush}"/>
506+
</VisualState.Setters>
507+
</VisualState>
508+
</VisualStateGroup>
509+
</VisualStateManager.VisualStateGroups>
510+
</Border>
511+
</ControlTemplate>
512+
</Setter.Value>
513+
</Setter>
514+
</Style>
515+
</ResourceDictionary>
516+
```
517+
518+
TemplatesResourceDictionary.xaml.cs
519+
520+
``` csharp
521+
// TemplatesResourceDictionary.xaml.cs
522+
using Microsoft.UI;
523+
using Microsoft.UI.Xaml;
524+
using Microsoft.UI.Xaml.Data;
525+
using Microsoft.UI.Xaml.Media;
526+
527+
namespace ExampleNamespace
528+
{
529+
public partial class TemplatesResourceDictionary
530+
{
531+
public TemplatesResourceDictionary()
532+
{
533+
InitializeComponent();
534+
}
535+
536+
// Properties for x:Bind - these are compile-time bound
537+
public SolidColorBrush DefaultIndicatorBrush { get; } =
538+
new SolidColorBrush(Colors.Green);
539+
540+
public SolidColorBrush DefaultPressedBrush { get; } =
541+
new SolidColorBrush(Colors.DarkGray);
542+
}
543+
}
544+
```
545+
546+
Usage in MainWindow.xaml with a ViewModel that provides runtime values:
547+
548+
``` xaml
549+
<!-- MainWindow.xaml -->
550+
<Window x:Class="ExampleNamespace.MainWindow"
551+
....
552+
xmlns:examplenamespace="using:ExampleNamespace">
553+
554+
<Window.Resources>
555+
<ResourceDictionary>
556+
<ResourceDictionary.MergedDictionaries>
557+
<examplenamespace:TemplatesResourceDictionary/>
558+
</ResourceDictionary.MergedDictionaries>
559+
</ResourceDictionary>
560+
</Window.Resources>
561+
562+
<Grid>
563+
<Grid.DataContext>
564+
<examplenamespace:ButtonThemeViewModel/>
565+
</Grid.DataContext>
566+
567+
<StackPanel Margin="20">
568+
<!-- These buttons use the mixed binding style -->
569+
<Button Content="Save" Style="{StaticResource CustomButtonStyle}"/>
570+
<Button Content="Cancel" Style="{StaticResource CustomButtonStyle}"/>
571+
</StackPanel>
572+
</Grid>
573+
</Window>
574+
```
575+
576+
ButtonThemeViewModel.cs (the DataContext that provides runtime binding values):
577+
578+
``` csharp
579+
using System.ComponentModel;
580+
using Microsoft.UI;
581+
using Microsoft.UI.Xaml.Media;
582+
583+
namespace ExampleNamespace
584+
{
585+
public class ButtonThemeViewModel : INotifyPropertyChanged
586+
{
587+
private SolidColorBrush _buttonBackgroundBrush = new SolidColorBrush(Colors.LightBlue);
588+
private SolidColorBrush _buttonForegroundBrush = new SolidColorBrush(Colors.DarkBlue);
589+
private SolidColorBrush _buttonHoverBrush = new SolidColorBrush(Colors.LightCyan);
590+
591+
public SolidColorBrush ButtonBackgroundBrush
592+
{
593+
get => _buttonBackgroundBrush;
594+
set
595+
{
596+
_buttonBackgroundBrush = value;
597+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonBackgroundBrush)));
598+
}
599+
}
600+
601+
public SolidColorBrush ButtonForegroundBrush
602+
{
603+
get => _buttonForegroundBrush;
604+
set
605+
{
606+
_buttonForegroundBrush = value;
607+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonForegroundBrush)));
608+
}
609+
}
610+
611+
public SolidColorBrush ButtonHoverBrush
612+
{
613+
get => _buttonHoverBrush;
614+
set
615+
{
616+
_buttonHoverBrush = value;
617+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonHoverBrush)));
618+
}
619+
}
620+
621+
public event PropertyChangedEventHandler PropertyChanged;
622+
}
623+
}
624+
```
625+
626+
In this example:
627+
628+
- **`{Binding}`** is used for properties that depend on the DataContext (ButtonBackgroundBrush, ButtonForegroundBrush, ButtonHoverBrush)
629+
- **`{x:Bind}`** is used for properties that are compile-time known and belong to the ResourceDictionary itself (DefaultIndicatorBrush, DefaultPressedBrush)
630+
- The style is reusable and can be applied to any Button
631+
- Runtime theming is possible through the DataContext while still benefiting from the performance of `{x:Bind}` for static elements
632+
442633
## Event binding and ICommand
443634

444635
[{x:Bind}](/windows/uwp/xaml-platform/x-bind-markup-extension) supports a feature called event binding. With this feature, you can specify the handler for an event using a binding, which is an additional option on top of handling events with a method on the code-behind file. Let's say you have a `ListViewDoubleTapped` event handler on your `MainWindow` class.

uwp/data-binding/data-binding-in-depth.md

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,192 @@ MainPage.xaml
589589
</Page>
590590
```
591591

592+
### Mixing {x\:Bind} and {Binding} in a reusable Style
593+
594+
While the previous example showed using {x:Bind} in DataTemplates, you can also create reusable Styles that combine both {x:Bind} and {Binding} markup extensions. This is useful when you want to bind some properties to compile-time known values using {x:Bind} and other properties to runtime DataContext values using {Binding}.
595+
596+
Here's an example that shows how to create a reusable Button style that uses both binding approaches:
597+
598+
TemplatesResourceDictionary.xaml
599+
600+
``` xaml
601+
<ResourceDictionary
602+
x:Class="ExampleNamespace.TemplatesResourceDictionary"
603+
.....
604+
xmlns:examplenamespace="using:ExampleNamespace">
605+
606+
<!-- DataTemplate using x:Bind -->
607+
<DataTemplate x:Key="EmployeeTemplate" x:DataType="examplenamespace:IEmployee">
608+
<Grid>
609+
<TextBlock Text="{x:Bind Name}"/>
610+
</Grid>
611+
</DataTemplate>
612+
613+
<!-- Style that mixes x:Bind and Binding -->
614+
<Style x:Key="CustomButtonStyle" TargetType="Button">
615+
<Setter Property="Background" Value="{Binding ButtonBackgroundBrush}"/>
616+
<Setter Property="Foreground" Value="{Binding ButtonForegroundBrush}"/>
617+
<Setter Property="FontSize" Value="16"/>
618+
<Setter Property="Margin" Value="4"/>
619+
<Setter Property="Template">
620+
<Setter.Value>
621+
<ControlTemplate TargetType="Button">
622+
<Border x:Name="RootBorder"
623+
Background="{TemplateBinding Background}"
624+
BorderBrush="{TemplateBinding BorderBrush}"
625+
BorderThickness="{TemplateBinding BorderThickness}"
626+
CornerRadius="4">
627+
<StackPanel Orientation="Horizontal"
628+
HorizontalAlignment="Center"
629+
VerticalAlignment="Center">
630+
<!-- x:Bind to a static property or page-level property -->
631+
<Ellipse Width="8" Height="8"
632+
Fill="{x:Bind DefaultIndicatorBrush}"
633+
Margin="0,0,8,0"/>
634+
<!-- Binding to DataContext -->
635+
<ContentPresenter x:Name="ContentPresenter"
636+
Content="{TemplateBinding Content}"
637+
Foreground="{TemplateBinding Foreground}"
638+
FontSize="{TemplateBinding FontSize}"/>
639+
</StackPanel>
640+
<VisualStateManager.VisualStateGroups>
641+
<VisualStateGroup x:Name="CommonStates">
642+
<VisualState x:Name="Normal"/>
643+
<VisualState x:Name="PointerOver">
644+
<VisualState.Setters>
645+
<!-- Binding to DataContext for hover color -->
646+
<Setter Target="RootBorder.Background"
647+
Value="{Binding ButtonHoverBrush}"/>
648+
</VisualState.Setters>
649+
</VisualState>
650+
<VisualState x:Name="Pressed">
651+
<VisualState.Setters>
652+
<!-- x:Bind to a compile-time known resource -->
653+
<Setter Target="RootBorder.Background"
654+
Value="{x:Bind DefaultPressedBrush}"/>
655+
</VisualState.Setters>
656+
</VisualState>
657+
</VisualStateGroup>
658+
</VisualStateManager.VisualStateGroups>
659+
</Border>
660+
</ControlTemplate>
661+
</Setter.Value>
662+
</Setter>
663+
</Style>
664+
</ResourceDictionary>
665+
```
666+
667+
TemplatesResourceDictionary.xaml.cs
668+
669+
``` csharp
670+
using Windows.UI;
671+
using Windows.UI.Xaml;
672+
using Windows.UI.Xaml.Data;
673+
using Windows.UI.Xaml.Media;
674+
675+
namespace ExampleNamespace
676+
{
677+
public partial class TemplatesResourceDictionary
678+
{
679+
public TemplatesResourceDictionary()
680+
{
681+
InitializeComponent();
682+
}
683+
684+
// Properties for x:Bind - these are compile-time bound
685+
public SolidColorBrush DefaultIndicatorBrush { get; } =
686+
new SolidColorBrush(Colors.Green);
687+
688+
public SolidColorBrush DefaultPressedBrush { get; } =
689+
new SolidColorBrush(Colors.DarkGray);
690+
}
691+
}
692+
```
693+
694+
Usage in MainPage.xaml with a ViewModel that provides runtime values:
695+
696+
``` xaml
697+
<Page x:Class="ExampleNamespace.MainPage"
698+
....
699+
xmlns:examplenamespace="using:ExampleNamespace">
700+
701+
<Page.Resources>
702+
<ResourceDictionary>
703+
<ResourceDictionary.MergedDictionaries>
704+
<examplenamespace:TemplatesResourceDictionary/>
705+
</ResourceDictionary.MergedDictionaries>
706+
</ResourceDictionary>
707+
</Page.Resources>
708+
709+
<Page.DataContext>
710+
<examplenamespace:ButtonThemeViewModel/>
711+
</Page.DataContext>
712+
713+
<StackPanel Margin="20">
714+
<!-- This button uses the mixed binding style -->
715+
<Button Content="Save" Style="{StaticResource CustomButtonStyle}"/>
716+
<Button Content="Cancel" Style="{StaticResource CustomButtonStyle}"/>
717+
</StackPanel>
718+
</Page>
719+
```
720+
721+
ButtonThemeViewModel.cs (the DataContext that provides runtime binding values):
722+
723+
``` csharp
724+
using System.ComponentModel;
725+
using Windows.UI;
726+
using Windows.UI.Xaml.Media;
727+
728+
namespace ExampleNamespace
729+
{
730+
public class ButtonThemeViewModel : INotifyPropertyChanged
731+
{
732+
private SolidColorBrush _buttonBackgroundBrush = new SolidColorBrush(Colors.LightBlue);
733+
private SolidColorBrush _buttonForegroundBrush = new SolidColorBrush(Colors.DarkBlue);
734+
private SolidColorBrush _buttonHoverBrush = new SolidColorBrush(Colors.LightCyan);
735+
736+
public SolidColorBrush ButtonBackgroundBrush
737+
{
738+
get => _buttonBackgroundBrush;
739+
set
740+
{
741+
_buttonBackgroundBrush = value;
742+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonBackgroundBrush)));
743+
}
744+
}
745+
746+
public SolidColorBrush ButtonForegroundBrush
747+
{
748+
get => _buttonForegroundBrush;
749+
set
750+
{
751+
_buttonForegroundBrush = value;
752+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonForegroundBrush)));
753+
}
754+
}
755+
756+
public SolidColorBrush ButtonHoverBrush
757+
{
758+
get => _buttonHoverBrush;
759+
set
760+
{
761+
_buttonHoverBrush = value;
762+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonHoverBrush)));
763+
}
764+
}
765+
766+
public event PropertyChangedEventHandler PropertyChanged;
767+
}
768+
}
769+
```
770+
771+
In this example:
772+
773+
- **{Binding}** is used for properties that depend on the DataContext (ButtonBackgroundBrush, ButtonForegroundBrush, ButtonHoverBrush)
774+
- **{x:Bind}** is used for properties that are compile-time known and belong to the ResourceDictionary itself (DefaultIndicatorBrush, DefaultPressedBrush)
775+
- The style is reusable and can be applied to any Button
776+
- Runtime theming is possible through the DataContext while still benefiting from the performance of {x:Bind} for static elements
777+
592778
## Event binding and ICommand
593779

594780
[{x:Bind}](../xaml-platform/x-bind-markup-extension.md) supports a feature called event binding. With this feature, you can specify the handler for an event using a binding, which is an additional option on top of handling events with a method on the code-behind file. Let's say you have a **RootFrame** property on your **MainPage** class.

0 commit comments

Comments
 (0)