The article presents generalized approaches to use
when writing XAML
-code.
IValueConverter
Data Binding
XAML
WPF
UWP
Xamarin Forms
UI
SwitchConverter
KeyToValueConverter
InlineConverter
AggregateConverter
ResourceDictionary
together with the data binding engine are important components in the development of user interfaces based on XAML
. Value converters imply the presence of logic in a separate class that implements the interface IValueConverter
. Typically, the class name reflects the functional purpose, and the instances are declared in the markup.
Switch Converter & Key To Value Converter
In practice, many converters have trivial logic values similar in structure to (?:)
or designs if-else
, switch-case-default
. However, there are generalized templates KeyToValueConverter
and SwitchConverter
that allow you to avoid adding classes of the same type in structure to the project by declaring boolean values and branches directly in the markup.
Concept
<KeyToValueConverter
Key="KeyForMatching"
Value="ValueIfKeyMatched"
ByDefault="ValueIfKeyNotMatched" />
<SwitchConverter
ByDefault="ValueZ">
<Case
Key="KeyA"
Value="ValueA" />
<Case
Key="KeyB"
Value="ValueB" />
<Case
Key="KeyC"
Value="ValueC" />
</SwitchConverter>
Application
<KeyToValueConverter
x:Key="TrueToVisibleConverter"
Key="True"
Value="Visible"
ByDefault="Collapsed" />
<ProgressBar
Visibility="{Binding IsBusy, Converter={StaticResource TrueToVisibleConverter}}" />
<SwitchConverter
x:Key="CodeToBackgroundConverter"
ByDefault="White">
<Case
Key="R"
Value="Red" />
<Case
Key="G"
Value="Green" />
<Case
Key="B"
Value="Blue" />
</SwitchConverter>
<Control
Background="{Binding Code, Converter={StaticResource CodeToBackgroundConverter}}" />
KeyToValueConverter
- Key
, , Value
, ByDefault
.
SwitchConverter
- Case
Key
, Case
, ¨C31C, ¨C90C¨C32C, .
Value
ByDefault
, , .
KeyToValueConverter
ConverterParameter
KeySource
<KeyToValueConverter
x:Key="EqualsToHiddenConverter"
KeySource="ConverterParameter"
Value="Collapsed"
ByDefault="Visible" />
<Control
Visiblity="{Binding Items.Count, ConverterParameter=0, Converter={StaticResource EqualsToHiddenConverter}}" />
<TextBlock
Visiblity="{Binding Text, ConverterParameter='Hide Me', Converter={StaticResource EqualsToHiddenConverter}}" />
KeySource
:
Manual
(by default
) - Key
,
ConverterParameter
- ConverterParameter
,
PreferManual
- manual Key
, ConverterParameter
PreferConverterParameter
- ConverterParameter
, manual Key
, SwitchConverter
Case
TypedCase
,
<SwitchConverter
ByDefault="Undefined value">
<TypedCase
Key="system:String"
Value="String value" />
<Case
Key="0"
Value="Zero" />
<Case
Key="1"
Value="One" />
<TypedCase
Key="system:Int32"
Value="Int32 value" />
</SwitchConverter>
. SwitchConverter
DiagnosticKey
, , Trace
var diagnosticMessage = matchedCase.Is()
? $"{DiagnosticKey}: '{matchedValue}' matched by key '{matchedCase.Key}' for '{value}' and converted to '{convertedValue}'"
: $"{DiagnosticKey}: The default value '{matchedValue}' matched for '{value}' and converted to '{convertedValue}'";
Trace.WriteLine(diagnosticMessage);
<SwitchConverter
DiagnosticKey="UniqDiagnosticKey"
x:Key="CodeToBackgroundConverter"
ByDefault="White">
...
</SwitchConverter>
Dependency Value Converter
Key
, Value
ByDefault
(Dependency Properties
), Case
s DependencyObject
. , , Binding
,
<KeyToValueConverter
Key="AnyKey"
Value="{Binding MatchedValue, Source={StaticResource AnyResource}}"
ByDefault="{Binding DefaultValue, Source={StaticResource AnyResource}}" />
<KeyToValueConverter
Key="AnyKey"
Value="{Localizing MatchedTitle}"
ByDefault="{Localizing DefaultTitle}" />
Inline Converter
, IValueConverter
, code-behind
.
, .
, code-behind
Converting
ConvertingBack
<Grid>
<Grid.Resources>
<InlineConverter
x:Key="ComplexInlineConverter"
Converting="InlineConverter_OnConverting"
ConvertingBack="InlineConverter_OnConverting" />
</Grid.Resources>
<TextBlock
Text="{Binding Number, Converter={StaticResource InlineConverter}}"/>
</Grid>
private void InlineConverter_OnConverting(object sender, ConverterEventArgs e)
{
// e.Value - access to input value
// this.DataContext - access to Data Context or another properties of the view
// access to child visual elements of this root view
e.ConvertedValue = // set output value
$"DataContext: {DataContext}, Converter Value: {e.Value}";
}
private void InlineConverter_OnConvertingBack(object sender, ConverterEventArgs e)
{
// ...
}
Aggregate Converter
, .
<AggregateConverter>
<StepAConverter />
<StepBConverter />
<StepCConverter />
</AggregateConverter>
App.xaml
It is useful to place generic value converters in a separate Resource Dictionary, and then merge them as global resources in the App.xaml file. This allows you to reuse value converters in different representations without re-declaring them.
<Application
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Any.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="AppConverters.xaml" />
...
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Ace Framework
Examples of implementation of the presented converters can be found in the Ace Framework
gitlab bitbucket library
With gratitude for your attention and interest!