[解決済み] 読み取り専用のGUIプロパティをViewModelにプッシュバックする
質問
Viewから読み取り専用の依存プロパティの現在の状態を常に知っているViewModelを書きたいと思っています。
具体的には、私のGUIは、FlowDocumentから一度に1ページを表示するFlowDocumentPageViewerを含んでいます。FlowDocumentPageViewer は、CanGoToPreviousPage および CanGoToNextPage という 2 つの読み取り専用の依存性プロパティを公開します。私は、私のViewModelがこれらの2つのViewプロパティの値を常に知っているようにしたい。
私はOneWayToSourceデータバインディングでこれを行うことができると考えました。
<FlowDocumentPageViewer
CanGoToNextPage="{Binding NextPageAvailable, Mode=OneWayToSource}" ...>
これが許可されていれば、完璧です。FlowDocumentPageViewerのCanGoToNextPageプロパティが変更されるたびに、新しい値はViewModelのNextPageAvailableプロパティに押し込まれるでしょう、これはまさに私が望むことです。
残念ながら、これはコンパイルされません。次のようなエラーが表示されます。 'CanGoToPreviousPage' プロパティは読み取り専用であり、マークアップから設定することはできません。 どうやら読み取り専用のプロパティは 任意の のようなデータバインディングをサポートしません。
私はViewModelのプロパティをDependencyPropertiesにすることができ、他の方法で行くOneWayバインディングを作ることができますが、私は分離概念違反について狂っていません(ViewModelはビューへの参照を必要とし、MVVMデータバインドは避けることになっている)。
FlowDocumentPageViewerはCanGoToNextPageChangedイベントを公開せず、私はDependencyPropertyから変更通知を取得する良い方法を知りません。
ビューの読み取り専用プロパティへの変更を ViewModel に通知し続けるにはどうしたらよいですか。
どのように解決するのですか?
はい、過去にこの方法を
ActualWidth
と
ActualHeight
プロパティがあり、どちらも読み取り専用になっています。付属のビヘイビアを作成し、そのビヘイビアに
ObservedWidth
と
ObservedHeight
が付属しています。また
Observe
プロパティがあり、これは最初のフックアップに使用されます。使い方は以下のようになります。
<UserControl ...
SizeObserver.Observe="True"
SizeObserver.ObservedWidth="{Binding Width, Mode=OneWayToSource}"
SizeObserver.ObservedHeight="{Binding Height, Mode=OneWayToSource}"
つまり、ビューモデルには
Width
と
Height
プロパティと常に同期している
ObservedWidth
と
ObservedHeight
が付属するプロパティです。このプロパティは
Observe
プロパティは単に
SizeChanged
イベントにアタッチするだけです。
FrameworkElement
. ハンドルの中で、それはその
ObservedWidth
と
ObservedHeight
のプロパティがあります。つまり
Width
と
Height
は、常にビューモデルの
ActualWidth
と
ActualHeight
の
UserControl
.
おそらく完璧な解決策ではありません(私もそう思います - 読み取り専用DPの
は
をサポートします。
OneWayToSource
のバインディングをサポートする必要があります)、しかしそれは動作し、MVVMパターンを支持しています。明らかに
ObservedWidth
と
ObservedHeight
DPは
ではなく
読み出し専用です。
UPDATE: 上記の機能を実装したコードはこちらです。
public static class SizeObserver
{
public static readonly DependencyProperty ObserveProperty = DependencyProperty.RegisterAttached(
"Observe",
typeof(bool),
typeof(SizeObserver),
new FrameworkPropertyMetadata(OnObserveChanged));
public static readonly DependencyProperty ObservedWidthProperty = DependencyProperty.RegisterAttached(
"ObservedWidth",
typeof(double),
typeof(SizeObserver));
public static readonly DependencyProperty ObservedHeightProperty = DependencyProperty.RegisterAttached(
"ObservedHeight",
typeof(double),
typeof(SizeObserver));
public static bool GetObserve(FrameworkElement frameworkElement)
{
frameworkElement.AssertNotNull("frameworkElement");
return (bool)frameworkElement.GetValue(ObserveProperty);
}
public static void SetObserve(FrameworkElement frameworkElement, bool observe)
{
frameworkElement.AssertNotNull("frameworkElement");
frameworkElement.SetValue(ObserveProperty, observe);
}
public static double GetObservedWidth(FrameworkElement frameworkElement)
{
frameworkElement.AssertNotNull("frameworkElement");
return (double)frameworkElement.GetValue(ObservedWidthProperty);
}
public static void SetObservedWidth(FrameworkElement frameworkElement, double observedWidth)
{
frameworkElement.AssertNotNull("frameworkElement");
frameworkElement.SetValue(ObservedWidthProperty, observedWidth);
}
public static double GetObservedHeight(FrameworkElement frameworkElement)
{
frameworkElement.AssertNotNull("frameworkElement");
return (double)frameworkElement.GetValue(ObservedHeightProperty);
}
public static void SetObservedHeight(FrameworkElement frameworkElement, double observedHeight)
{
frameworkElement.AssertNotNull("frameworkElement");
frameworkElement.SetValue(ObservedHeightProperty, observedHeight);
}
private static void OnObserveChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
var frameworkElement = (FrameworkElement)dependencyObject;
if ((bool)e.NewValue)
{
frameworkElement.SizeChanged += OnFrameworkElementSizeChanged;
UpdateObservedSizesForFrameworkElement(frameworkElement);
}
else
{
frameworkElement.SizeChanged -= OnFrameworkElementSizeChanged;
}
}
private static void OnFrameworkElementSizeChanged(object sender, SizeChangedEventArgs e)
{
UpdateObservedSizesForFrameworkElement((FrameworkElement)sender);
}
private static void UpdateObservedSizesForFrameworkElement(FrameworkElement frameworkElement)
{
// WPF 4.0 onwards
frameworkElement.SetCurrentValue(ObservedWidthProperty, frameworkElement.ActualWidth);
frameworkElement.SetCurrentValue(ObservedHeightProperty, frameworkElement.ActualHeight);
// WPF 3.5 and prior
////SetObservedWidth(frameworkElement, frameworkElement.ActualWidth);
////SetObservedHeight(frameworkElement, frameworkElement.ActualHeight);
}
}
関連
-
WPFバインディング(データバインディング)の使用方法
-
[解決済み】WPFでMVVMを使ったダイアログの扱いについて
-
[解決済み】WPFコンボボックスのカスタムリストへのバインド
-
[解決済み] 静的プロパティへのバインディング
-
[解決済み] wpf: ボタンがコマンドによって無効にされたとき、ツールチップを表示する方法は?
-
[解決済み] DataTrigger where value is NOT null?
-
[解決済み] スタックパネルでアイテムを整列させる?
-
[解決済み] WPF:幅(と高さ)をパーセント値で設定する
-
[解決済み] WPF フォントのぼやけ問題- 解決策
-
[解決済み] Generic.xamlの特徴とは?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] StackPanelの子パネルが下方向に最大限のスペースを埋めるようにするには?
-
[解決済み] Windows 8 ランタイム(WinRT / Windowsストアアプリ / Windows 10 ユニバーサルアプリ)とSilverlightやWPFの比較はどうですか?[クローズド]
-
[解決済み] [Solved] StackPanelの子要素をスペースアウトさせるには?
-
[解決済み] WPFでデータトリガーに複数の条件を指定するには?
-
[解決済み] オーバーレイコントロールを他のすべてのコントロールの上に配置するには?
-
[解決済み] DataTrigger where value is NOT null?
-
[解決済み] WPF: スクロールバー付きItemsControl (ScrollViewer)
-
[解決済み] Prism for WPFとは?
-
[解決済み] 読み取り専用のGUIプロパティをViewModelにプッシュバックする
-
[解決済み] ViewModelLocatorとは何ですか?また、DataTemplatesと比較した場合の長所と短所は何ですか?