在xaml中绑定矩形的宽度和高度

6

我正在尝试将ViewPort中的Rect的宽度和高度绑定如下:

<VisualBrush.Viewport>
    <Rect Width="{Binding Path=MyWidth}" Height="{Binding Path=MyHeight}"/>
</VisualBrush.Viewport>

我的绑定在其他地方很好用,但这里出现以下错误信息:

无法在类型为“Rect”的“Width”属性上设置“Binding”。只能在DependencyObject的DependencyProperty上设置“Binding”。

编辑 我理解了错误信息。我的问题是如何解决它。我如何绑定rect的高度和宽度?


错误信息非常清晰。Rect 结构的属性不可绑定,因为它们不是依赖属性。 - Clemens
那么没有办法做到这一点吗? - Daltons
VisualBrush.Viewport 是一个依赖属性。您可以使用多绑定为 Viewport 属性创建一个转换器,该转换器从两个源值创建一个 Rect。 - Clemens
你可以使用多边形(Polygon)代替矩形(Rectangle),并将PointsProperty绑定到该对象,作为一种解决方法。在代码中仍然可以使用矩形,但需要在属性getter中将其转换为点类型。 - N Jacobs
@NJacobs,你不能将多边形用作VisualBrush的Viewport属性的值。它的类型是Rect。 - Clemens
@Clemens 哦,是的,你说得对,我的错。 - N Jacobs
2个回答

8

可以使用MultiBinding,如下所示:

<VisualBrush.Viewport>
    <MultiBinding>
        <MultiBinding.Converter>
            <local:RectConverter/>
        </MultiBinding.Converter>
        <Binding Path="MyWidth"/>
        <Binding Path="MyHeight"/>
    </MultiBinding>
</VisualBrush.Viewport>

使用像这样的多值转换器:

public class RectConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return new Rect(0d, 0d, (double)values[0], (double)values[1]);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

1
谢谢,它有效。由于某种原因,当我开始输入时,MultiBinding没有显示为建议的条目,所以我以为它不能与Viewport一起使用。 - Daltons

-2

更新的答案: Rect是一个结构体,Height和Width不是依赖属性(请参见屏幕截图),因此无法绑定到任何东西。

enter image description here

使用依赖属性和绑定的方法如下:

MyRect类带有依赖属性:

 public class MyRect : DependencyObject,INotifyPropertyChanged
{
    public MyRect()
    {            
        this.Rect = new Rect(0d, 0d, (double)Width, (double)Height);      
    }      

    private Rect rect;

    public Rect Rect
    {
        get { return rect; }
        set 
        {
            rect = value;
            RaiseChange("Rect");
        }
    }

    public double Height
    {
        get { return (double)GetValue(HeightProperty); }
        set { SetValue(HeightProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Height.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty HeightProperty =
        DependencyProperty.Register("Height", typeof(double), typeof(MyRect), new UIPropertyMetadata(1d, OnHeightChanged));

    public static void OnHeightChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
    {
        if (e.NewValue != null)
        {
            var MyRect = (dp as MyRect);
            var hight = Convert.ToDouble(e.NewValue);
            MyRect.Rect = new Rect(0d, 0d, MyRect.Rect.Width, hight);                
        }
    }

    public double Width
    {
        get { return (double)GetValue(WidthProperty); }
        set { SetValue(WidthProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Width.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty WidthProperty =
        DependencyProperty.Register("Width", typeof(double), typeof(MyRect), new UIPropertyMetadata(1d, OnWidthChanged));

    public static void OnWidthChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
    {
        if (e.NewValue != null)
        {
            var MyRect = (dp as MyRect);
            var width = Convert.ToDouble(e.NewValue);
            MyRect.Rect = new Rect(0d, 0d, width, MyRect.Rect.Height);
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaiseChange(string prop)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }
    }

}  

视图:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public MainWindow()
    {           
        InitializeComponent();
        MyRect = new TabControl.MyRect();            
    }

    private MyRect myRect;
    public MyRect MyRect
    {
        get { return myRect; }
        set { myRect = value; RaiseChange("MyRect");}
    }             

    private void MySlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    {
        if (MyRect != null)
        {
            MyRect.Height = e.NewValue/10;
            MyRect.Width = e.NewValue/10;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void RaiseChange(string prop)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }
    }
}

XAML:

<Window x:Class="TabControl.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
    xmlns:local="clr-namespace:TabControl"
    Title="MainWindow" Height="450" Width="525"       
    DataContext="{Binding RelativeSource={RelativeSource Self}}"        
    >
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="80*"/>
        <RowDefinition Height="80"/>
    </Grid.RowDefinitions>        
    <Rectangle Name="recLogin" Height="300"  Width="400" DataContext="{Binding MyRect}" >
        <Rectangle.Fill>
            <VisualBrush TileMode="None" Viewport="{Binding Rect}">                    
                <VisualBrush.Visual>
                    <ScrollViewer Height="30" Width="100">
                        <Button Content="Transparent" Height="30"  Width="80" />
                    </ScrollViewer>
                </VisualBrush.Visual>
            </VisualBrush>
        </Rectangle.Fill>
    </Rectangle>        
    <Slider Maximum="20" x:Name="MySlider" Value="4" TickFrequency="1" Grid.Row="1"  TickPlacement="TopLeft" ValueChanged="MySlider_ValueChanged" />
</Grid>

输出:

Larger

Smaller


1
哇,你既没有读问题也没有读任何评论。我再说一遍:你不能使用除Rect以外的任何东西作为VisualBrush.Viewport属性的值。 - Clemens
@Clemens 我实际上没有仔细阅读问题。谢谢指出。因此学到了一两件事情。 - Kylo Ren

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接