WPF: Twoway привязка между 4 текстовыми коробками и 1 границей. Маргин

StackOverflow https://stackoverflow.com/questions/3925453

Вопрос

Я хочу установить пограницу границы границы USERCONTROL, используя 4 текстовых ящика, но я не могу заставить его работать.

Код 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>

Преобразователь необходим для анализа ввода строки в текстовом поле:

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

Текстовое поле правильно отображает левую часть толщины, но редактирование текстового поля не приводит к изменению в том случае, если левая сторона границы отображается. Как ни странно, значение, которое я установил в текстовом поле для толщины .LEFT, сохраняется, поэтому кажется, что значение настроен, но рендеринг не обновляется. В примере кода изменение значения в текстовом поле, а затем изменение визуализации окна показывает, что граница слева делает дополнительное пространство, но это пространство пустое.

Кто-нибудь знает, как понять и исправить это?

Это было полезно?

Решение

Он не динамически обновляет элемент на экране, потому что ничего не говорил элементу, что поле в его 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");
        }
    }
}

Другие советы

Я полагаю, что это укажет вас в правильном направлении: читать на полпути вниз, он имеет 2 способа приближения к этому, один с преобразователем и один без.

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

Самое простое решение для меня оказывается, чтобы просто слушать текстовое мероприятие TextBox и замените границу в коде позади.

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

Прямо сейчас это работает для меня, решение Роберта Россени лучше.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top