Подтвердить что ты не робот

Проблемы с привязкой к высоте и ширине окна

У меня есть некоторые проблемы, когда я пытаюсь связать высоту и ширину окна с свойствами в моей модели представления. Вот небольшое примерное приложение, чтобы проиллюстрировать проблему. Это код в app.xaml.xs

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
       base.OnStartup(e);
        MainWindow mainWindow = new MainWindow();
        MainWindowViewModel mainWindowViewModel = new MainWindowViewModel();
        mainWindow.DataContext = mainWindowViewModel;
        mainWindow.Show();
    }
}

Это MainWindow.xaml:

<Window x:Class="TestApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Height="{Binding WindowHeight}" 
        Width="{Binding WindowWidth}"
        BorderThickness="{Binding WindowBorderThickness}">
</Window>

И это модель представления:

public class MainWindowViewModel
{
    public int WindowWidth { get { return 100; } }
    public int WindowHeight { get { return 200; } }
    public int WindowBorderThickness { get { return 8; } }
}

Когда программа запускается, вызываются геттеры WindowHeight и WindowBorderThickness (но не WindowWidth), поэтому высота и граница окна установлены правильно, но не ширина.

Затем я добавляю кнопку, которая вызовет PropertyChanged для всех свойств, так что теперь модель вида выглядит следующим образом:

public class MainWindowViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void TriggerPropertyChanges()
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs("WindowWidth"));
            PropertyChanged(this, new PropertyChangedEventArgs("WindowHeight"));
            PropertyChanged(this, new PropertyChangedEventArgs("WindowBorderThickness"));
        }

    }

    public ICommand ButtonCommand { get { return new RelayCommand(delegate { TriggerPropertyChanges(); }); } }

    public int WindowWidth { get { return 100; } }
    public int WindowHeight { get { return 200; } }
    public int WindowBorderThickness { get { return 8; } }
}

Теперь, когда я нажимаю кнопку, вызывается получатель WindowBorderThickness, но не те, что для WindowWidth и WindowHeight. Все это кажется мне очень странным и непоследовательным. Что мне не хватает?

4b9b3361

Ответ 1

Я постараюсь ответить на собственный вопрос. Связывания работают, но мы не можем быть уверены, что система макета запрашивает, например, свойство Width окна.

Из MSDN:

Если этот элемент является дочерним элементом внутри какого-либо другого элемента, то установка этого свойства в значение действительно является только рекомендуемым значением. Система макета, а также конкретная логика компоновки родительского элемента будут использовать значение в качестве непереплетного ввода во время процесса компоновки. На практике термин FrameworkElement почти всегда является дочерним элементом чего-то другого; даже когда вы устанавливаете "Высота по окну". (Для окна это значение используется, когда базовая модель приложения устанавливает базовые предположения рендеринга, которые создают Hwnd, на котором размещается приложение.)

Решение, которое, похоже, работает, связано с привязкой свойства WindowWidth к MinWidth и MaxWidth, а также к ширине. Один из них будет извлечен, по крайней мере, в тестовом сценарии, который я использовал выше.

Ответ 2

Попробуйте использовать двустороннюю привязку, это сработало для меня:

Width="{Binding Path=xExt, Mode=TwoWay}"

Ответ 3

У меня была та же проблема, и я заметил, что это зависит от того, будет ли высота или ширина записываться сначала в xaml. Если высота первая, тогда привязка работает только для нее и наоборот. Решением было установить режим привязки на "TwoWay": Проект, который я сделал, был с MS Studio 2010 и .NET 4.0

Ответ 4

Кроме того, вы можете использовать SizeToContent="WidthAndHeight" с MinHeight и MinWidth, поэтому для MaxHeight и MaxWidth не потребуется дополнительный вызов.

Ответ 5

ОК,

У меня была такая же проблема, и я не смог правильно привязать размер окна (мин, макс, нормальный) к моей модели просмотра через XAML.

Я не знаю, почему, но вы можете получить все эти привязки без каких-либо проблем, если вы делаете их по коду вместо XAML.

Вот мой код С#, который работал:

this.SetBinding(Window.WidthProperty, new Binding("Width") { Source = MyViewModel, Mode=BindingMode.TwoWay });
this.SetBinding(Window.HeightProperty, new Binding("Height") { Source = MyViewModel, Mode=BindingMode.TwoWay });
this.SetBinding(Window.MaxWidthProperty, new Binding("MaxWidth") { Source = MyViewModel });
this.SetBinding(Window.MaxHeightProperty, new Binding("MaxHeight") { Source = MyViewModel });
this.SetBinding(Window.MinWidthProperty, new Binding("MinWidth") { Source = MyViewModel });
this.SetBinding(Window.MinHeightProperty, new Binding("MinHeight") { Source = MyViewModel });

Странно, что он работает только в коде, а не в XAML. Еще страннее, что он связывает TwoWay по умолчанию для измерений mMin и Max, но не для нормальных измерений, для которых вы должны указать "Mode = BindingMode.TwoWay".

Должна быть ошибка, которую Microsoft должна исправить об этом...

Ответ 6

Привязка к MinWidth и MinHeight верна. Кроме того, если вам требуется привязка к MaxWidth и MaxHeight, если ваша динамика увеличит или уменьшит размер окна.

Ответ 7

Я не уверен в вашей конкретной реализации, но я просто пишу пример, который может быть полезен.

XAML

<Window x:Name="MainWindow"
    x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" 
    MinWidth="200"
    MinHeight="100"
    Width="{Binding ElementName=MainWindow, Path=WindowWidth}"
    Height="{Binding ElementName=MainWindow, Path=WindowHeight}">
    <Grid>
        <Slider 
            x:Name="slWidth" 
            Value="{Binding ElementName=MainWindow, Path=WindowWidth, Mode=TwoWay}"
            Minimum="200"
            Maximum="1600"
            Height="23" HorizontalAlignment="Left" Margin="56,22,0,0" VerticalAlignment="Top" Width="61" />
        <Label 
            Content="Width" 
            Height="28" 
            HorizontalAlignment="Left" 
            Margin="12,22,0,0" 
            Name="Label1" 
            VerticalAlignment="Top" />
        <Slider 
            x:Name="slHeight" 
            Value="{Binding ElementName=MainWindow, Path=WindowHeight, Mode=TwoWay}"
            Minimum="100"
            Maximum="800"
            Height="23" HorizontalAlignment="Left"  VerticalAlignment="Top" Width="61" Margin="56,51,0,0" />
        <Label 
            Content="Height" 
            Height="28" 
            HorizontalAlignment="Left"              
            VerticalAlignment="Top" Margin="12,46,0,0" />
    </Grid>
</Window>

код

Class MainWindow

    Public Shared ReadOnly WindowWidthProperty As DependencyProperty = _
                           DependencyProperty.Register("WindowWidth", _
                           GetType(Integer), GetType(MainWindow), _
                           New FrameworkPropertyMetadata(Nothing))

    Public Shared ReadOnly WindowHeightProperty As DependencyProperty = _
                         DependencyProperty.Register("WindowHeight", _
                         GetType(Integer), GetType(MainWindow), _
                         New FrameworkPropertyMetadata(Nothing))

    Public Property WindowWidth As Integer
        Get
            Return CInt(GetValue(WindowWidthProperty))
        End Get
        Set(ByVal value As Integer)
            SetValue(WindowWidthProperty, value)
        End Set
    End Property

    Public Property WindowHeight As Integer
        Get
            Return CInt(GetValue(WindowHeightProperty))
        End Get
        Set(ByVal value As Integer)
            SetValue(WindowHeightProperty, value)
        End Set
    End Property


End Class

Код С#

public readonly DependencyProperty WindowWidthProperty = DependencyProperty.Register("WindowWidth", typeof(Double), typeof(MainWindow), new FrameworkPropertyMetadata());
public readonly DependencyProperty WindowHeightProperty = DependencyProperty.Register("WindowHeight", typeof(Double), typeof(MainWindow), new FrameworkPropertyMetadata());

public double WindowWidth {
    get { return Convert.ToDouble(this.GetValue(WindowWidthProperty)); }
    set { this.SetValue(WindowWidthProperty, value); }
}

public double WindowHeight {
    get { return Convert.ToDouble(this.GetValue(WindowHeightProperty)); }
    set { this.SetValue(WindowHeightProperty, value); }
}

Ответ 8

Я не думаю, что вы можете установить размер окна динамически