Jak pominąć aktualizację niektórych sub-wiązań o MultiBinding
? Mam zdefiniowane w kodzie-za (miałem pewne kłopoty czyni go w XAML i nie sądzę, jest to ważne - w końcu kodu źródłowego nie mniej ekspresyjny jest następnie XAML) A MultiBinding
który trwa dwie właściwości tylko do odczytu i jedno normalne właściwość do wytworzenia jednej wartości. W przypadku ConvertBack
właściwości tylko do odczytu nie są modyfikowane (oni podtrzymywać ich wartości), a tylko normalna właściwość zostanie zmieniona.TwoWay MultiBinding z tylko do odczytu właściwości
Podczas definicji MultiBinding
cała MultiBinding
został ustawiony TwoWay
jednak poszczególne pod-wiązanie, w którym ustala odpowiednie (pierwsze dwa OneWay
i trzeci dwóch TwoWay
).
Problem występuje we własnym zakresie. Jednak ze względu na prezentację uprośniłem go do mniejszej kontroli. Kontrolą przedstawioną w tym przykładzie jest kontrola podobna do Slider
, pozwalająca wybrać wartość w [0,0; 1,0] zasięgu. Wybrana wartość jest reprezentowana przez kciuk i jest wyświetlana jako DependencyProperty
.
Zasadniczo, kontrola jest zbudowany przez 1 wiersz x 3 kolumny Grid
gdzie kciuk znajduje się w środkowej kolumnie. Aby prawidłowo ustawić lewą kolumnę kciuka, należy przypisać szerokość odpowiadającą wybranej pozycji. Jednakże szerokość ta zależy również od rzeczywistej szerokości całego sterowania i rzeczywistej szerokości samego kciuka (to dlatego, że położenie jest podana jako wartość względną w [0,0; 1,0] Zakres).
Gdy kciuk zostanie przeniesiony stanowisko powinno zostać zaktualizowane jednak odpowiednio szerokość i szerokość kciuka kontrola oczywiście nie zmieni.
Kod działa zgodnie z oczekiwaniami, ale po uruchomieniu w IDE podczas przemieszczania kciuka Okno wyjściowe jest zaśmiecone informacjami o wyjątkach zgłaszanymi, gdy MultiBinding
próbuje ustawić wartość tych dwóch właściwości tylko do odczytu. Podejrzewam, że nie jest to szkodliwe, ale jest nieco denerwujące i mylące. A także oznacza, że kod robi coś innego, niż chciałem, aby to zrobić, ponieważ nie chciałem ustawiać tych właściwości (ma to znaczenie na wypadek, gdyby nie były tylko do odczytu, a to by je zmodyfikowało).
MultiBinding
documentation w sekcji Uwagi wspomina, że poszczególne powiązania podrzędne mogą przesłonić wartość trybu MultiBinding
, ale wydaje się, że nie działa.
Być może można to w jakiś sposób rozwiązać, wyrażając zależność od kontroli i szerokości kciuka (właściwości tylko do odczytu) w jakiś sposób inaczej. Na przykład osobno rejestruje się powiadomienia i wymusza aktualizację po ich zmianie. Jednak nie wydaje mi się to naturalne. MultiBinding
działa z drugiej strony, ponieważ po lewej szerokości kolumny zależy od tych trzech właściwości.
Oto przykład kodu 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>
I tu jest odpowiedni kod z opóźnieniem
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);
}
}
}
}
Dzięki; tego właśnie potrzebowałem wiedzieć! Czy istnieje prosty sposób uzyskania wartości wejściowych tych właściwości w ConvertBack? –
Dzięki! Warto również wspomnieć o indywidualnych "wewnętrznych" wiązaniach, które mają zostać przekonwertowane na wartość, i które powinny być ustawione na "Mode = TwoWay". Nie znalazłem tego w dokumentacji. : / –