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

Почему 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 не начнет исправлять ошибку.

4b9b3361

Ответ 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}"