#c# #wpf #xaml
#wpf #mvvm #центрирование
Вопрос:
Я работаю над очень простым приложением, использующим собственные WPF и MVVM. Основное представление «оболочки» использует, как я считаю, общий базовый шаблон, в котором он содержит ContentControl, привязанный к данным активной viewmodel, которая вводит представление через шаблоны данных. Это сокращенная версия того, как это выглядит:
<Window.DataContext>
<local:ShellViewModel/>
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="{x:Type local:DbConfigViewModel}">
<local:DbConfigView/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:AuthenticationViewModel}">
<local:AuthenticationView/>
</DataTemplate>
</Window.Resources>
<DockPanel>
<ContentControl Content="{Binding CurrentViewModel}"/>
</DockPanel>
Для этого окна установлен автоматический размер в зависимости от вида, и оно настроено на запуск по центру. Это отлично работает для первоначального представления. Однако некоторые представления намного больше, и это становится проблемой пользовательского интерфейса, когда они становятся активными. Что мне нужно, так это чтобы приложение перецентрировалось при каждом изменении представления.
До сих пор я пытался привязать к данным свойства Left и Top главного окна, например:
<Window (....)
Width="auto" Height="auto"
SizeToContent="WidthAndHeight"
WindowStartupLocation="CenterScreen"
Left="{Binding WindowLeft}"
Top="{Binding WindowTop}">
Моя навигация привязана к методу в viewmodel основного окна Windows, поэтому в этом методе после того, как для нового viewmodel установлено свойство CurrentViewModel, я затем вызываю этот метод:
private void CenterWindow()
{
Rect workArea = System.Windows.SystemParameters.WorkArea;
WindowLeft = (workArea.Width - Application.Current.MainWindow.Width) / 2 workArea.Left;
WindowTop = (workArea.Height - Application.Current.MainWindow.Height) / 2 workArea.Top;
}
Кажется, что это должно сработать, но, похоже, происходит то, что MainWindow .Ширина и высота еще не были скорректированы, поэтому центрирование выполняется на основе предыдущего представления, а не того, которое я только что создал.
Итак, есть ли какое-то событие или другое место для вызова этого кода, чтобы оно происходило после отображения нового представления? Это вообще правильный подход?
Комментарии:
1. если вы уверены, что размер окна не может быть изменен пользователем, я думаю, вы сможете сделать это, создав переопределение onSizeChanged для главного окна и вызвав там CenterWindow ? Примечание: MSDN описывает
WorkArea
, как получает размер рабочей области на основном мониторе отображения. таким образом, ваш метод не всегда будет делать то, что вы ожидаете от него в системах с несколькими мониторами2. Я думал о событии onSizeChanged, но я не хотел мешать способности клиента изменять размер окна. В качестве последнего средства мы подумаем об удалении этой возможности, но я хотел бы найти другой способ, если это возможно. Спасибо за совет о workArea, я не знал об этом.
3. Можете ли вы показать мне какое- либо профессиональное приложение с таким поведением? Я предполагаю, что вы не можете, и это потому, что это плохая идея. Изменение размера приложения
Window
(если оно не является дочернимWindow
) не должно быть проблемой команды разработчиков. Создайте гибкий пользовательский интерфейс, который максимально подходит для всех видов, и оставьте размерWindow
на усмотрение пользователя… как и должно было быть . Я бы сказал, что тот факт, что вы задаете этот вопрос, указывает на то, что у вас что-то не так с дизайном вашего пользовательского интерфейса.4. @Sheridan Хотя я обычно соглашаюсь с вами, это конкретное приложение представляет собой очень простую утилиту, которую я разрабатываю для нашей команды инженерных служб. Основная часть приложения — это единый вид, однако мне нужно, чтобы они прошли через 2 коротких диалоговых окна, прежде чем попасть туда. Вместо того, чтобы использовать традиционные диалоговые службы, я решил, что было бы достаточно просто просто поменять вид, как я показал. Это был быстрый и простой способ завершить задачу, но мне просто нужно решить этот маленький нюанс.
5. Это то, что я не могу понять … гибкий пользовательский интерфейс WPF поместится в любое пространство, предоставленное содержащим
Window
… кажется, что это то, чего вам на самом деле не хватает, и как вы должны исправить этот маленький нюанс , как вы его называете.
Ответ №1:
Затем вам нужно подписаться на SizeChanged в вашем окне:
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (e.PreviousSize == e.NewSize)
return;
var w = SystemParameters.PrimaryScreenWidth;
var h = SystemParameters.PrimaryScreenHeight;
this.Left = (w - e.NewSize.Width) / 2;
this.Top = (h - e.NewSize.Height) / 2;
}
Вы можете использовать события взаимодействия, если хотите, в своей ViewModel
Комментарии:
1. Что делать, если окна нет на основном экране?