将只读GUI属性推回ViewModel

将只读GUI属性推回ViewModel

我想要写一个视图模型,它总是知道视图中某些只读依赖属性的当前状态。

具体来说,我的GUI包含一个FlowDocumentPageViewer,它每次从FlowDocument中显示一个页面。FlowDocumentPageViewer公开了两个名为CanGoToPreviousPage和CanGoToNextPage的只读依赖项属性。我希望我的ViewModel始终知道这两个View属性的值。

我想我可以通过OneWayToSource数据库实现这一点:

<FlowDocumentPageViewer
    CanGoToNextPage="{Binding NextPageAvailable, Mode=OneWayToSource}" ...>

如果允许这样做,它将是完美的:每当FlowDocumentPageViewer的CanGoToNextPage属性更改时,新的值将被向下推到ViewModel的NextPageAvailable属性中,这正是我想要的。

不幸的是,这不能编译:我收到一个错误的说法“CanGoToPreviousPage”属性是只读的,不能从标记中设置。显然只读属性不支持任何这是一种数据绑定,甚至不是针对该属性的只读数据。

我可以将ViewModel的属性变成DependencyProperties,并使OneWay绑定向相反的方向发展,但我并不热衷于关注点冲突的分离(ViewModel需要引用视图,MVVM数据库应该避免这种情况)。

FlowDocumentPageViewer不公开CanGoToNextPageChanged事件,而且我也不知道从DependencyProperty获取更改通知的任何好方法,除非创建另一个DependencyProperty来绑定它,这在这里似乎有点过分。

如何将视图只读属性的更改通知ViewModel?


隔江千里
浏览 375回答 3
3回答

当年话下

我使用的是一种通用解决方案,它不仅适用于ActualWidth和ActualHL.8,而且还适用于至少在读取模式下可以绑定到的任何数据。如果ViewportWidth和ViewportHL.8是视图模型的属性,则标记如下<Canvas> &nbsp;&nbsp;&nbsp;&nbsp;<u:DataPiping.DataPipes> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<u:DataPipeCollection> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<u:DataPipe&nbsp;Source="{Binding&nbsp;RelativeSource={RelativeSource&nbsp;AncestorType={x:Type&nbsp;Canvas}},&nbsp;Path=ActualWidth}" &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Target="{Binding&nbsp;Path=ViewportWidth,&nbsp;Mode=OneWayToSource}"/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<u:DataPipe&nbsp;Source="{Binding&nbsp;RelativeSource={RelativeSource&nbsp;AncestorType={x:Type&nbsp;Canvas}},&nbsp;Path=ActualHeight}" &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Target="{Binding&nbsp;Path=ViewportHeight,&nbsp;Mode=OneWayToSource}"/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</u:DataPipeCollection> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</u:DataPiping.DataPipes><Canvas>以下是自定义元素的源代码public&nbsp;class&nbsp;DataPiping{ &nbsp;&nbsp;&nbsp;&nbsp;#region&nbsp;DataPipes&nbsp;(Attached&nbsp;DependencyProperty) &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;readonly&nbsp;DependencyProperty&nbsp;DataPipesProperty&nbsp;= &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DependencyProperty.RegisterAttached("DataPipes", &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typeof(DataPipeCollection), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typeof(DataPiping), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;UIPropertyMetadata(null)); &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;SetDataPipes(DependencyObject&nbsp;o,&nbsp;DataPipeCollection&nbsp;value) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;o.SetValue(DataPipesProperty,&nbsp;value); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;DataPipeCollection&nbsp;GetDataPipes(DependencyObject&nbsp;o) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(DataPipeCollection)o.GetValue(DataPipesProperty); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;#endregion}public&nbsp;class&nbsp;DataPipeCollection&nbsp;:&nbsp;FreezableCollection<DataPipe>{}public&nbsp;class&nbsp;DataPipe&nbsp;:&nbsp;Freezable{ &nbsp;&nbsp;&nbsp;&nbsp;#region&nbsp;Source&nbsp;(DependencyProperty) &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;object&nbsp;Source &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;get&nbsp;{&nbsp;return&nbsp;(object)GetValue(SourceProperty);&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set&nbsp;{&nbsp;SetValue(SourceProperty,&nbsp;value);&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;readonly&nbsp;DependencyProperty&nbsp;SourceProperty&nbsp;= &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DependencyProperty.Register("Source",&nbsp;typeof(object),&nbsp;typeof(DataPipe), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;FrameworkPropertyMetadata(null,&nbsp;new&nbsp;PropertyChangedCallback(OnSourceChanged))); &nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;static&nbsp;void&nbsp;OnSourceChanged(DependencyObject&nbsp;d,&nbsp;DependencyPropertyChangedEventArgs&nbsp;e) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((DataPipe)d).OnSourceChanged(e); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;virtual&nbsp;void&nbsp;OnSourceChanged(DependencyPropertyChangedEventArgs&nbsp;e) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Target&nbsp;=&nbsp;e.NewValue; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;#endregion &nbsp;&nbsp;&nbsp;&nbsp;#region&nbsp;Target&nbsp;(DependencyProperty) &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;object&nbsp;Target &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;get&nbsp;{&nbsp;return&nbsp;(object)GetValue(TargetProperty);&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set&nbsp;{&nbsp;SetValue(TargetProperty,&nbsp;value);&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;readonly&nbsp;DependencyProperty&nbsp;TargetProperty&nbsp;= &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DependencyProperty.Register("Target",&nbsp;typeof(object),&nbsp;typeof(DataPipe), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;FrameworkPropertyMetadata(null)); &nbsp;&nbsp;&nbsp;&nbsp;#endregion &nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;override&nbsp;Freezable&nbsp;CreateInstanceCore() &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;DataPipe(); &nbsp;&nbsp;&nbsp;&nbsp;}}

catspeake

如果其他人感兴趣,我在这里编写了Kent的近似解:class&nbsp;SizeObserver{ &nbsp;&nbsp;&nbsp;&nbsp;#region&nbsp;"&nbsp;Observe&nbsp;" &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;bool&nbsp;GetObserve(FrameworkElement&nbsp;elem) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(bool)elem.GetValue(ObserveProperty); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;SetObserve( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FrameworkElement&nbsp;elem,&nbsp;bool&nbsp;value) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elem.SetValue(ObserveProperty,&nbsp;value); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;readonly&nbsp;DependencyProperty&nbsp;ObserveProperty&nbsp;= &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DependencyProperty.RegisterAttached("Observe",&nbsp;typeof(bool),&nbsp;typeof(SizeObserver), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;UIPropertyMetadata(false,&nbsp;OnObserveChanged)); &nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;void&nbsp;OnObserveChanged( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DependencyObject&nbsp;depObj,&nbsp;DependencyPropertyChangedEventArgs&nbsp;e) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FrameworkElement&nbsp;elem&nbsp;=&nbsp;depObj&nbsp;as&nbsp;FrameworkElement; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(elem&nbsp;==&nbsp;null) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(e.NewValue&nbsp;is&nbsp;bool&nbsp;==&nbsp;false) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;((bool)e.NewValue) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elem.SizeChanged&nbsp;+=&nbsp;OnSizeChanged; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elem.SizeChanged&nbsp;-=&nbsp;OnSizeChanged; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;void&nbsp;OnSizeChanged(object&nbsp;sender,&nbsp;RoutedEventArgs&nbsp;e) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!Object.ReferenceEquals(sender,&nbsp;e.OriginalSource)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FrameworkElement&nbsp;elem&nbsp;=&nbsp;e.OriginalSource&nbsp;as&nbsp;FrameworkElement; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(elem&nbsp;!=&nbsp;null) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetObservedWidth(elem,&nbsp;elem.ActualWidth); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetObservedHeight(elem,&nbsp;elem.ActualHeight); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;#endregion &nbsp;&nbsp;&nbsp;&nbsp;#region&nbsp;"&nbsp;ObservedWidth&nbsp;" &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;double&nbsp;GetObservedWidth(DependencyObject&nbsp;obj) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(double)obj.GetValue(ObservedWidthProperty); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;SetObservedWidth(DependencyObject&nbsp;obj,&nbsp;double&nbsp;value) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj.SetValue(ObservedWidthProperty,&nbsp;value); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Using&nbsp;a&nbsp;DependencyProperty&nbsp;as&nbsp;the&nbsp;backing&nbsp;store&nbsp;for&nbsp;ObservedWidth.&nbsp;&nbsp;This&nbsp;enables&nbsp;animation,&nbsp;styling,&nbsp;binding,&nbsp;etc... &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;readonly&nbsp;DependencyProperty&nbsp;ObservedWidthProperty&nbsp;= &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DependencyProperty.RegisterAttached("ObservedWidth",&nbsp;typeof(double),&nbsp;typeof(SizeObserver),&nbsp;new&nbsp;UIPropertyMetadata(0.0)); &nbsp;&nbsp;&nbsp;&nbsp;#endregion &nbsp;&nbsp;&nbsp;&nbsp;#region&nbsp;"&nbsp;ObservedHeight&nbsp;" &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;double&nbsp;GetObservedHeight(DependencyObject&nbsp;obj) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(double)obj.GetValue(ObservedHeightProperty); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;SetObservedHeight(DependencyObject&nbsp;obj,&nbsp;double&nbsp;value) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj.SetValue(ObservedHeightProperty,&nbsp;value); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Using&nbsp;a&nbsp;DependencyProperty&nbsp;as&nbsp;the&nbsp;backing&nbsp;store&nbsp;for&nbsp;ObservedHeight.&nbsp;&nbsp;This&nbsp;enables&nbsp;animation,&nbsp;styling,&nbsp;binding,&nbsp;etc... &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;readonly&nbsp;DependencyProperty&nbsp;ObservedHeightProperty&nbsp;= &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DependencyProperty.RegisterAttached("ObservedHeight",&nbsp;typeof(double),&nbsp;typeof(SizeObserver),&nbsp;new&nbsp;UIPropertyMetadata(0.0)); &nbsp;&nbsp;&nbsp;&nbsp;#endregion}在您的应用程序中可以随意使用它。效果很好。(谢谢肯特!)
打开App,查看更多内容
随时随地看视频慕课网APP