为了账号安全,请及时绑定邮箱和手机立即绑定

将只读GUI属性推回ViewModel

将只读GUI属性推回ViewModel

隔江千里 2019-07-27 15:15:36
将只读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?
查看完整描述

3 回答

?
当年话下

TA贡献1890条经验 获得超9个赞

我使用的是一种通用解决方案,它不仅适用于ActualWidth和ActualHL.8,而且还适用于至少在读取模式下可以绑定到的任何数据。

如果ViewportWidth和ViewportHL.8是视图模型的属性,则标记如下

<Canvas>
    <u:DataPiping.DataPipes>
         <u:DataPipeCollection>
             <u:DataPipe Source="{Binding RelativeSource={RelativeSource AncestorType={x:Type Canvas}}, Path=ActualWidth}"
                         Target="{Binding Path=ViewportWidth, Mode=OneWayToSource}"/>
             <u:DataPipe Source="{Binding RelativeSource={RelativeSource AncestorType={x:Type Canvas}}, Path=ActualHeight}"
                         Target="{Binding Path=ViewportHeight, Mode=OneWayToSource}"/>
          </u:DataPipeCollection>
     </u:DataPiping.DataPipes><Canvas>

以下是自定义元素的源代码

public class DataPiping{
    #region DataPipes (Attached DependencyProperty)

    public static readonly DependencyProperty DataPipesProperty =
        DependencyProperty.RegisterAttached("DataPipes",
        typeof(DataPipeCollection),
        typeof(DataPiping),
        new UIPropertyMetadata(null));

    public static void SetDataPipes(DependencyObject o, DataPipeCollection value)
    {
        o.SetValue(DataPipesProperty, value);
    }

    public static DataPipeCollection GetDataPipes(DependencyObject o)
    {
        return (DataPipeCollection)o.GetValue(DataPipesProperty);
    }

    #endregion}public class DataPipeCollection : FreezableCollection<DataPipe>{}public class DataPipe : Freezable{
    #region Source (DependencyProperty)

    public object Source
    {
        get { return (object)GetValue(SourceProperty); }
        set { SetValue(SourceProperty, value); }
    }
    public static readonly DependencyProperty SourceProperty =
        DependencyProperty.Register("Source", typeof(object), typeof(DataPipe),
        new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnSourceChanged)));

    private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((DataPipe)d).OnSourceChanged(e);
    }

    protected virtual void OnSourceChanged(DependencyPropertyChangedEventArgs e)
    {
        Target = e.NewValue;
    }

    #endregion

    #region Target (DependencyProperty)

    public object Target
    {
        get { return (object)GetValue(TargetProperty); }
        set { SetValue(TargetProperty, value); }
    }
    public static readonly DependencyProperty TargetProperty =
        DependencyProperty.Register("Target", typeof(object), typeof(DataPipe),
        new FrameworkPropertyMetadata(null));

    #endregion

    protected override Freezable CreateInstanceCore()
    {
        return new DataPipe();
    }}



查看完整回答
反对 回复 2019-07-28
?
catspeake

TA贡献1111条经验 获得超0个赞

如果其他人感兴趣,我在这里编写了Kent的近似解:

class SizeObserver{
    #region " Observe "

    public static bool GetObserve(FrameworkElement elem)
    {
        return (bool)elem.GetValue(ObserveProperty);
    }

    public static void SetObserve(
      FrameworkElement elem, bool value)
    {
        elem.SetValue(ObserveProperty, value);
    }

    public static readonly DependencyProperty ObserveProperty =
        DependencyProperty.RegisterAttached("Observe", typeof(bool), typeof(SizeObserver),
        new UIPropertyMetadata(false, OnObserveChanged));

    static void OnObserveChanged(
      DependencyObject depObj, DependencyPropertyChangedEventArgs e)
    {
        FrameworkElement elem = depObj as FrameworkElement;
        if (elem == null)
            return;

        if (e.NewValue is bool == false)
            return;

        if ((bool)e.NewValue)
            elem.SizeChanged += OnSizeChanged;
        else
            elem.SizeChanged -= OnSizeChanged;
    }

    static void OnSizeChanged(object sender, RoutedEventArgs e)
    {
        if (!Object.ReferenceEquals(sender, e.OriginalSource))
            return;

        FrameworkElement elem = e.OriginalSource as FrameworkElement;
        if (elem != null)
        {
            SetObservedWidth(elem, elem.ActualWidth);
            SetObservedHeight(elem, elem.ActualHeight);
        }
    }

    #endregion

    #region " ObservedWidth "

    public static double GetObservedWidth(DependencyObject obj)
    {
        return (double)obj.GetValue(ObservedWidthProperty);
    }

    public static void SetObservedWidth(DependencyObject obj, double value)
    {
        obj.SetValue(ObservedWidthProperty, value);
    }

    // Using a DependencyProperty as the backing store for ObservedWidth.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ObservedWidthProperty =
        DependencyProperty.RegisterAttached("ObservedWidth", typeof(double), typeof(SizeObserver), new UIPropertyMetadata(0.0));

    #endregion

    #region " ObservedHeight "

    public static double GetObservedHeight(DependencyObject obj)
    {
        return (double)obj.GetValue(ObservedHeightProperty);
    }

    public static void SetObservedHeight(DependencyObject obj, double value)
    {
        obj.SetValue(ObservedHeightProperty, value);
    }

    // Using a DependencyProperty as the backing store for ObservedHeight.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ObservedHeightProperty =
        DependencyProperty.RegisterAttached("ObservedHeight", typeof(double), typeof(SizeObserver), new UIPropertyMetadata(0.0));

    #endregion}

在您的应用程序中可以随意使用它。效果很好。(谢谢肯特!)




查看完整回答
反对 回复 2019-07-28
  • 3 回答
  • 0 关注
  • 373 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信