Почему WindowStartupLocation = CenterScreen помещает мое окно где-то, кроме центра экрана?
Здесь объявление окна:
<Window
x:Class="Pse.ExperimentBase.SplashWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Style="{StaticResource _windowStyle}"
WindowStartupLocation="CenterScreen"
WindowStyle="None">
Здесь объявление стиля:
<Style
x:Key="_windowStyle"
TargetType="Window">
<Setter
Property="Width"
Value="{Binding Path=InitialWindowWidth}" />
<Setter
Property="Height"
Value="{Binding Path=InitialWindowHeight}" />
<Setter
Property="Icon"
Value="Resources/MyIcon.ico" />
<Setter
Property="Background"
Value="{StaticResource _fadedOrangeBrush}" />
<Setter
Property="FontSize"
Value="11" />
</Style>
Обсуждение:
Экран 1280 X 1024. Размер окна (определяемый связями InitialWindowWidth, InitialWindowHeight) составляет 800 X 600.
Когда откроется окно, появится 188, 141 (слева, сверху). Это в основном "северо-запад", где это должно быть. Если я вычисляю истинно центрированные значения, это должно быть 240, 212 (слева, сверху).
Ключ?
Это всегда первое окно, в котором есть проблема. Если я открою второй экземпляр того же окна, он будет отображаться в правильном месте.
Другой ключ?
Второй экземпляр окна будет отображаться только в правильном месте, если я создам оба экземпляра перед открытием первого.
Итак...
Window win1 = windowFactory.CreateSplashWindow();
win1.Show();
Window win2 = windowFactory.CreateSplashWindow();
win2.Show();
win1.Hide();
... смещает как win1, так и win2
Но...
Window win1 = windowFactory.CreateSplashWindow();
Window win2 = windowFactory.CreateSplashWindow();
win1.Show();
win2.Show();
win1.Hide();
... смещает win1, но показывает мертвую точку win2.
Итак, мой вопрос:
Что здесь происходит???
EDIT:
Еще одна подсказка. Если я добавлю...
Width="800"
Height="600"
... в мое объявление Window, проблема смещения исчезает. Однако это не решение для меня, потому что размер окна должен быть сохранен в файле настроек. Вот почему у меня есть привязка данных в моем стиле. (И обратите внимание, что привязка данных к ширине и высоте работает отлично - все окна отображаются как правильный размер).
РЕДАКТИРОВАТЬ № 2:
Я проверял ширину и высоту в режиме отладки и пришел к этому интересному выводу:
Если я создаю несколько экземпляров окна, но не открываю никаких окон, свойства Width и Height для всех экземпляров окна "NaN".
Если я открываю только один из экземпляров, свойства ширины и высоты для каждого экземпляра окна являются неожиданно действительными числами, а не только шириной и высотой окна, которое я открыл.
Это говорит мне, что WPF откладывает привязку данных до тех пор, пока в первом окне не будет выведено Show().
→ Итак, теперь возникает вопрос: могу ли я заставить WPF выполнять привязку данных до того, как я покажу первое окно?
Изменить # 3:
Я только что представил представленный Microsoft отчет об ошибке в этом выпуске. Вот ссылка:
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=477598
Изменить # 4: Обходное решение
Реального разрешения пока нет, но я только что подтвердил, что вы можете обойти проблему, используя фиктивное окно. Выполните следующие действия:
- Создайте новое окно XPF под названием "BlankWindow" (см. ниже XAML).
- Создайте экземпляр BlankWindow и окно, на которое вы хотите по центру (FirstWindow).
- Выполните следующую последовательность кода:
...
BlankWindow.Show()
FirstWindow.Show()
BlankWindow.Hide()
XAML для моего фиктивного окна - не более того:
<Window
x:Class="Pse.ExperimentBase.Windows.BlankWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="BlankWindow"
Height="0"
Width="0"
WindowStyle="None">
<Grid></Grid>
</Window>
Я не вижу заметного мерцания до того, как откроется "FirstWindow", поэтому я считаю это достаточно хорошим решением, пока MS не начнет исправлять ошибку.
Ответы
Ответ 1
Могут ли ваши привязки Width
и Height
мешать? Если вы вообще не устанавливаете Width
и Height
, появляется ли окно в правильном месте? Если это так, это то же место, что и когда у вас есть привязки, установленные выше?
Если все это правда, то похоже, что WPF вычисляет расположение окна до получения значений Width
и Height
из ваших привязок. Я не уверен в хорошем способе обойти это - возможно, сначала установите Width
и Height
вручную (либо в XAML, либо в конструкторе), а затем настройте привязки после его отображения?
Ответ 2
Я не вижу ссылок на поля в ваших примерах. Тем не менее, я часто разочаровываюсь, когда Visual Studio меняет поля для элементов (когда они находятся в сетке) после перетаскивания стороны объекта в конструкторе (я бы подумал, что это изменит его ширину, а не ее маржу). И, имея странные поля, могут возникнуть непредвиденные проблемы с размещением.
Ответ 3
Это довольно старый пост, но поскольку я не мог найти правильного решения, у меня есть еще одна работа:
Вы можете рассчитать местоположение своего диалога вручную (http://social.msdn.microsoft.com/Forums/eu/wpf/thread/054800c3-56dc-4700-a2fb-d2b79fc9ef9a).
Не очень элегантный, но он работает:
public class Controller
{
private Double CalcCoordinate(Double parentCoordinate, Double parentSize, Double thisSize)
{
return parentCoordinate + (parentSize - thisSize) / 2;
}
public Controller(Double width, Double height, Window owner)
{
Width = width;
Height = height;
Left = CalcCoordinate(owner.Left, owner.Width, Width);
Top = CalcCoordinate(owner.Top, owner.Height, Height);
}
public Double Width { get; set; }
public Double Height { get; set; }
public Double Left { get; set; }
public Double Top { get; set; }
}
Затем просто привяжите расположение и размер окна к этим свойствам и не забудьте изменить WindowStartupLocation на Manual.
По какой-то причине я просто не получаю, Top/Left должен быть привязан в режиме TwoWay, я не мог заставить его работать правильно без него.
Ответ 4
Еще одно обходное решение... добавьте возвращаемое значение в привязки.
Width="{Binding Width, FallbackValue=500}" Height="{Binding Height, FallbackValue=500}"