Comment passer la mise à jour de certaines sous-liaisons d'un MultiBinding
? J'ai défini dans code-behind (j'ai eu quelques problèmes en le faisant en XAML et je ne pense pas que cela compte - après tout code-behind n'est pas moins expressif que XAML) un MultiBinding
qui prend deux propriétés en lecture seule et une propriété normale pour produire une seule valeur. Dans le cas de ConvertBack
, les propriétés en lecture seule ne sont pas modifiées (elles conservent leur valeur) et seule la propriété normale est modifiée.TwoWay MultiBinding avec des propriétés en lecture seule
Bien que la définition de la MultiBinding
l'ensemble MultiBinding
a été fixée à TwoWay
toutefois sous-ensemble approprié des liaisons où (première à deux OneWay
et le troisième deux TwoWay
) particuliers.
Le problème se produit dans un mon propre contrôle. Cependant, pour des raisons de présentation, je l'ai simplifié à un plus petit contrôle. Le contrôle présenté dans cet exemple est un contrôle similaire à Slider
permettant de sélectionner une valeur dans [0.0; 1,0] plage. La valeur sélectionnée est représentée par le pouce et exposée en tant que DependencyProperty
.
Fondamentalement, le contrôle est construit par une colonne 1 x 3 Grid
où le pouce est dans la colonne du milieu. Pour positionner correctement la colonne à gauche du pouce, il faut attribuer une largeur correspondant à la position sélectionnée. Cependant, cette largeur dépend également de la largeur réelle du contrôle entier et de la largeur réelle du pouce lui-même (car la position est donnée comme une valeur relative dans la plage [0.0; 1.0]). Lorsque le pouce est déplacé, la position doit être mise à jour de manière appropriée, mais la largeur du pouce et la largeur du contrôle ne changent évidemment pas. Le code fonctionne comme prévu mais lorsqu'il est exécuté dans l'EDI pendant le déplacement du pouce La fenêtre de sortie est encombrée avec des informations d'exceptions comme indiqué lorsque MultiBinding
essaie de définir la valeur de ces deux propriétés en lecture seule. Je soupçonne que ce n'est pas dangereux, mais il est un peu ennuyeux et trompeur. Et cela signifie aussi que le code fait quelque chose d'autre que je voulais faire car je ne voulais pas définir ces propriétés (ceci est important dans le cas où elles ne seraient pas en lecture seule et que cela les modifierait en fait).
MultiBinding
documentation dans Remarques La section mentionne que les sous-liaisons individuelles sont autorisées à remplacer la valeur du mode MultiBinding
, mais cela ne semble pas fonctionner.
Peut-être que cela pourrait être résolu d'une manière ou d'une autre en exprimant la dépendance sur le contrôle et les largeurs de pouce (les propriétés en lecture seule) d'une manière ou d'une autre. Par exemple, l'inscription à leurs notifications séparément et l'application de mise à jour lors de leur modification. Cependant cela ne me semble pas naturel. D'autre part, MultiBinding
car après tout la largeur de la colonne de gauche dépend de ces trois propriétés.
Voici l'exemple de code XAML.
<UserControl x:Class="WpfTest.ExampleUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="leftColumn" />
<ColumnDefinition x:Name="thumbColumn" Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!-- Rectangle used in the left column for better visualization. -->
<Rectangle Grid.Column="0">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="Black" Offset="0" />
<GradientStop Color="White" Offset="1" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<!-- Thumb representing the Position property. -->
<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Center" />
<!-- Rectangle used in the right column for better visualization. -->
<Rectangle Grid.Column="2">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="White" Offset="0" />
<GradientStop Color="Black" Offset="1" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
</UserControl>
Et voici le code-behind correspondant
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace WpfTest
{
public partial class ExampleUserControl : UserControl
{
#region PositionConverter
private class PositionConverter : IMultiValueConverter
{
public PositionConverter(ExampleUserControl owner)
{
this.owner = owner;
}
#region IMultiValueConverter Members
public object Convert(
object[] values,
Type targetType,
object parameter,
CultureInfo culture)
{
double thisActualWidth = (double)values[0];
double thumbActualWidth = (double)values[1];
double position = (double)values[2];
double availableWidth = thisActualWidth - thumbActualWidth;
double leftColumnWidth = availableWidth * position;
return new GridLength(leftColumnWidth);
}
public object[] ConvertBack(
object value,
Type[] targetTypes,
object parameter,
CultureInfo culture)
{
double thisActualWidth = owner.ActualWidth;
double thumbActualWidth = owner.thumbColumn.ActualWidth;
GridLength leftColumnWidth = (GridLength)value;
double availableWidth = thisActualWidth - thumbActualWidth;
double position;
if (availableWidth == 0.0)
position = 0.0;
else
position = leftColumnWidth.Value/availableWidth;
return new object[] {
thisActualWidth, thumbActualWidth, position
};
}
#endregion
private readonly ExampleUserControl owner;
}
#endregion
public ExampleUserControl()
{
InitializeComponent();
MultiBinding leftColumnWidthBinding = new MultiBinding()
{
Bindings =
{
new Binding()
{
Source = this,
Path = new PropertyPath("ActualWidth"),
Mode = BindingMode.OneWay
},
new Binding()
{
Source = thumbColumn,
Path = new PropertyPath("ActualWidth"),
Mode = BindingMode.OneWay
},
new Binding()
{
Source = this,
Path = new PropertyPath("Position"),
Mode = BindingMode.TwoWay
}
},
Mode = BindingMode.TwoWay,
Converter = new PositionConverter(this)
};
leftColumn.SetBinding(
ColumnDefinition.WidthProperty, leftColumnWidthBinding);
}
public static readonly DependencyProperty PositionProperty =
DependencyProperty.Register(
"Position",
typeof(double),
typeof(ExampleUserControl),
new FrameworkPropertyMetadata(0.5)
);
public double Position
{
get
{
return (double)GetValue(PositionProperty);
}
set
{
SetValue(PositionProperty, value);
}
}
}
}
Merci; c'est ce que j'avais besoin de savoir! Y at-il un moyen facile d'obtenir les valeurs d'entrée de ces propriétés dans un ConvertBack? –
Merci! Peut-être que cela vaut la peine de mentionner également les différentes liaisons «internes» pour lesquelles vous voulez que la valeur soit reconvertie en mode «Mode = TwoWay». Je n'ai pas trouvé cela dans la documentation. : / –