gpt4 book ai didi

wpf - 具有只读属性的 TwoWay MultiBinding

转载 作者:行者123 更新时间:2023-12-03 01:16:06 24 4
gpt4 key购买 nike

如何跳过更新MultiBinding的一些子绑定(bind)?我已经在代码隐藏中定义了一个 MultiBinding ,它需要两次读取-仅属性和一个普通属性生成单个值。在 ConvertBack 的情况下,只读属性不会被修改(它们维持其值),并且只会更改普通属性。

在定义 MultiBinding 时,整个 MultiBinding 设置为 TwoWay,但是设置适当的特定子绑定(bind)(前两个设置为 OneWay 和第三个 TwoWay)。

<小时/>

问题出现在我自己的控件中。然而,为了演示的目的,我将其简化为更小的控件。此示例中呈现的控件是类似 Slider 的控件,允许选择 [0.0; 中的值; 1.0]范围。所选值由拇指表示并作为 DependencyProperty 公开。

基本上,该控件由 1 行 x 3 列网格构建,其中拇指位于中间列。为了正确定位拇指左列,必须分配与所选位置相对应的宽度。然而,这个宽度还取决于整个控件的实际宽度和拇指本身的实际宽度(这是因为位置是以 [0.0; 1.0] 范围内的相对值给出的)。

当拇指移动时,位置应该适当更新,但拇指宽度和控件宽度显然不会改变。

代码按预期工作,但是当拇指移动期间在 IDE 中运行时,输出窗口中充满了当 MultiBinding 尝试为这两个只读属性设置值时报告的异常信息。我怀疑它没有害处,但它有点烦人和误导。这也意味着代码做了一些我想要它做的事情,因为我不想设置这些属性(这很重要,以防它们不是只读的,这实际上会修改它们)。

多重绑定(bind) documentation在“备注”部分提到允许单个子绑定(bind)覆盖 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>

这是相应的隐藏代码

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);
}
}

}
}

最佳答案

最后我自己找到了解决方案。实际上它在documentation中- 我不知道我是怎么错过的,但我为此付出了高昂的代价(浪费了时间)。

根据文档ConvertBack应该返回Binding.DoNothing在不设置任何值的位置上(特别是需要 OneWay 绑定(bind))。另一个特殊值是 DependencyProperty.UnsetValue .

这不是一个完整的解决方案,就像现在 IMultiValueConverter实现必须知道在哪里返回特殊值。不过我认为这个解决方案涵盖了大多数合理的情况。

关于wpf - 具有只读属性的 TwoWay MultiBinding,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1767432/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com