1

4 つの TextBox を使用して UserControl の Border の BorderThickness を設定したいのですが、うまくいきません。

問題を示す XAML コード (コンバーターと組み合わせたこのコードのみが必要です):

<Window 
    x:Class="BorderThicknessBindingTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:BorderThicknessBindingTest="clr-namespace:BorderThicknessBindingTest" 
    Height="300" Width="500">
    <Window.Resources>
        <BorderThicknessBindingTest:ThicknessConverter x:Key="ThicknessConverter"/>
    </Window.Resources>

    <Grid Margin="10">
        <Border 
            x:Name="MyBorder"
            BorderBrush="Black" 
            Background="AliceBlue"
            BorderThickness="3"/>
        <TextBox 
            HorizontalAlignment="Center" VerticalAlignment="Center"
            Text="{Binding Path=BorderThickness.Left, ElementName=MyBorder, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource ThicknessConverter}}"/>
    </Grid>
</Window>

TextBox に入力された文字列を解析するには、コンバーターが必要です。

public class ThicknessConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value; // don't need to do anything here
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        double d;
        Double.TryParse((string) value, out d); // Thickness.Left doesn't take a string
        return d;
    }
}

TextBox は Thickness の Left 部分を正しく表示しますが、TextBox を編集しても、Border の左側がレンダリングされる方法は変わりません。奇妙なことに、Thickness.Left の TextBox に設定した値が保持されるため、値が設定されているように見えますが、レンダリングは更新されません。サンプル コードでは、TextBox の値を変更してから Window のサイズを変更すると、左側の境界線が追加のスペースを占有することを示していますが、このスペースは空白です。

これを修正する方法を知っている人はいますか?

4

3 に答える 3

2

BorderThicknessプロパティのフィールドが変更されたことを要素に伝えていないため、画面上の要素を動的に更新していません。変更されたことを要素に通知する必要がBorderThicknessあります。これは、依存関係プロパティを新しい値に直接設定することによってのみ行うことができます。たとえば、通知を変更するオブジェクトへのバインディングのターゲットにすることによってのみ可能です。

このためのビュー モデルを作成するのは少し面倒ですが、作成したら完了です。

窓:

<Window x:Class="ThicknessDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ComponentModel="clr-namespace:System.ComponentModel;assembly=System" xmlns:ThicknessDemo="clr-namespace:ThicknessDemo" Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <ThicknessDemo:ThicknessViewModel x:Key="thickness" />
    </Window.Resources>
        <DockPanel DataContext="{StaticResource thickness}">
            <Border DockPanel.Dock="Top"
                    Width="100"
                    Height="50"
                    Margin="5"
                    BorderBrush="Blue"
                    BorderThickness="{Binding Thickness}" />
            <TextBox DockPanel.Dock="Top"
                        Text="{Binding Left, Mode=TwoWay}" />
            <TextBox DockPanel.Dock="Top"
                        Text="{Binding Right, Mode=TwoWay}" />
            <TextBox DockPanel.Dock="Top"
                        Text="{Binding Top, Mode=TwoWay}" />
            <TextBox DockPanel.Dock="Top"
                        Text="{Binding Bottom, Mode=TwoWay}" />
            <TextBlock DockPanel.Dock="Top" />
        </DockPanel>
</Window>

ビュー モデル:

public class ThicknessViewModel : INotifyPropertyChanged
{
    private void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler h = PropertyChanged;
        if (h != null)
        {
            h(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public ThicknessViewModel()
    {
        _Thickness = new Thickness(1, 1, 1, 1);
    }

    private Thickness _Thickness;

    public Thickness Thickness { get { return _Thickness; } set { _Thickness = value;} }

    public double Left
    {
        get { return _Thickness.Left; }
        set
        {
            _Thickness.Left = value;
            OnPropertyChanged("Thickness");
        }
    }

    public double Right
    {
        get { return _Thickness.Right; }
        set
        {
            _Thickness.Right = value;
            OnPropertyChanged("Thickness");
        }
    }

    public double Top
    {
        get { return _Thickness.Top; }
        set
        {
            _Thickness.Top = value;
            OnPropertyChanged("Thickness");
        }
    }

    public double Bottom
    {
        get { return _Thickness.Bottom; }
        set
        {
            _Thickness.Bottom = value;
            OnPropertyChanged("Thickness");
        }
    }
}
于 2010-10-13T18:25:45.737 に答える
1

これは正しい方向を示すと思います。途中で読むと、コンバーターを使用する方法と使用しない方法の2つの方法があります。

http://10rem.net/blog/2010/05/08/breaking-apart-the-margin-property-in-xaml-for-better-binding

于 2010-10-13T15:57:56.493 に答える
0

私にとって最も簡単な解決策は、TextBox の TextChanged イベントをリッスンし、コード ビハインドで BorderThickness を置き換えることです。

MainWindow.xaml:

<Window 
    x:Class="BorderThicknessBindingTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:BorderThicknessBindingTest="clr-namespace:BorderThicknessBindingTest" 
    Height="300" Width="500">

    <Grid Margin="10">
        <Border 
            x:Name="MyBorder"
            BorderBrush="Black" 
            Background="AliceBlue"
            BorderThickness="3"/>
        <TextBox 
            x:Name="MyTextBox"
            HorizontalAlignment="Center" VerticalAlignment="Center"
            Text="{Binding Path=BorderThickness.Left, ElementName=MyBorder, Mode=OneWay}"/>
    </Grid>
</Window>

コンストラクター内の MainWindow.xaml.cs:

MyTextBox.TextChanged += (sender, e) =>
{
    double d;
    if (!double.TryParse(MyTextBox.Text, out d)) return;
    var t = MyBorder.BorderThickness;
    t.Left = d;
    MyBorder.BorderThickness = t;
};

今のところこれでうまくいきます.Robert Rossneyのソリューションの方が優れています.

于 2010-10-14T12:36:39.393 に答える