26796


Livetを使ってデスクトップアクセサリのようなものを作っているのですが、ViewModel側からウィンドウの位置・サイズを変えたくて以下のような記述をXAMLに書きました。

[code]

    <Window x:Class="LivetWPFApplication1.Views.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
            xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
            xmlns:vm="clr-namespace:LivetWPFApplication1.ViewModels"
    
            MinWidth="{Binding Width}" MinHeight="{Binding Height}"
            MaxWidth="{Binding Width}" MaxHeight="{Binding Height}"
            Left="{Binding Left}" Top="{Binding Top}">
        ...
    </Window>
    
[/code]

※Top, Left, Width, Heightの各プロパティはlpropスニペットでdouble型で作成しています

これでWidthやHeightは上手くいったのですが、LeftとTopの更新が反映されません。

ViewModelのコンストラクタ内で設定した値は効いているようですが、別途バインドしたコントロールから変更したり、LivetのViewModelテンプレートにある`Initialize()`
内で変更したりしてもウィンドウの位置が変化しません。

（あるいはウィンドウ位置の操作にはMessengerを使うべきなのでしょうか？）


CC BY-SA 3.0
2016-06-16T12:43:31.950
26792
2016-06-21T14:22:42.443
8000
question
wpf
ウィンドウの位置をBindingで設定しても値の更新が反映されない


WPFの`Window`ではウィンドウを表示すると`Left`や`Top`などのプロパティのバインディング設定が消えてしまうという現象が発生します。なので添付プロパティ等を使った`Window.Left`にバインドしない実装を使用する必要があります。


CC BY-SA 3.0
2016-06-16T14:15:46.020
26796
2016-06-16T14:15:46.020
5750
26792
answer


（詳細が気になったので調べた結果を書きます）

WPFの `Window` クラスはウィンドウが表示されるときや手動でリサイズされたとき、依存関係プロパティ `Left` `Top` `Width`
`Height` に実際のウィンドウから得た値を設定します。

この時 `BindingMode.OneWay`
でバインディングが行われていると、既存のバインディング設定を消去した上で値が設定されるため、今回のような挙動になっていたようです。

ということを踏まえた回避策としては、

  * `BindingMode.TwoWay` でバインドする  
（前述の場面でWindow側から値が設定される）

  * 直接バインドすることを避ける  
（添付プロパティやBehaviorを使ってバインドする、Messengerを使うなど）

といったところでしょうか。

参考

  * [OneWay binding stops working after the target manually updated - Stack Overflow](https://stackoverflow.com/q/598139/2818869)


CC BY-SA 3.0
2016-06-21T14:22:42.443
26922
2016-06-21T14:22:42.443
2017-05-23T12:38:55.250
-1
8000
26792
answer