如何跳过更新一些子绑定MultiBinding?我已经在代码隐藏中定义了(我在XAML中遇到了一些麻烦,我觉得这不重要 - 毕竟代码隐藏不是那么表达,而是XAML)a MultiBinding需要两个只读属性和一个普通属性产生单一价值.如果ConvertBack不修改只读属性(它们维持其值)并且仅更改普通属性.
虽然定义了MultiBinding整个MultiBinding被设置为TwoWay特定的子绑定设置适当(前两个到OneWay第三个TwoWay).
问题出现在我自己的控件中.然而,为了便于演示,我将其简化为较小的控件.此示例中显示Slider的控件是类似控件,允许选择[0.0; 1.0]范围.所选值由拇指表示并显示为a DependencyProperty.
基本上,控制是由1行x 3列构建的,Grid其中拇指位于中间列中.要正确定位拇指,左列必须指定与所选位置对应的宽度.然而,这个宽度还取决于整个控件的实际宽度和拇指本身的实际宽度(这是因为位置是[0.0; 1.0]范围内的相对值).
移动拇指时,应适当更新位置,但拇指宽度和控制宽度显然不会改变.
代码按预期工作,但是在拇指移动期间在IDE中运行时,当MultiBinding尝试将值设置为这两个只读属性时,"输出"窗口会混乱出现异常信息.我怀疑它没有害处,但有点烦人和误导.并且它意味着代码执行其他事情然后我希望它做,因为我不想设置这些属性(这在他们不是只读的情况下很重要,这实际上会修改它们).
MultiBinding 备注部分中的文档提到允许单个子绑定覆盖MultiBinding模式值,但它似乎不起作用.
也许这可以通过以某种方式表达对控件和拇指宽度(只读属性)的依赖性以某种方式解决.例如,单独注册其通知并在更改时强制执行更新.然而,这对我来说似乎并不自然.MultiBinding另一方面,因为所有左列宽度确实取决于这三个属性.
这是示例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>
Run Code Online (Sandbox Code Playgroud)
这里是相应的代码隐藏
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);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
Ada*_*ura 11
最后我自己找到了解决方案.实际上它在文档中 - 我不知道我是如何错过的,但我为此付出了沉重的代价(浪费时间).
根据文件ConvertBack应该返回Binding.DoNothing没有设置值的位置(特别OneWay是需要绑定).另一个特殊价值是DependencyProperty.UnsetValue.
这不是一个完整的解决方案,因为现在IMultiValueConverter实现必须知道返回特殊值的位置.但是我认为这个解决方案涵盖了大多数合理的案例.
| 归档时间: |
|
| 查看次数: |
3246 次 |
| 最近记录: |