【问题标题】:TwoWay Binding Not Updating双向绑定未更新
【发布时间】:2018-07-26 20:29:46
【问题描述】:

我添加了一个 ScrollViewer 行为,当基于 Scroll the scrollviewer to top through viewmodel 将属性设置为 true 时,该行为允许我滚动到顶部。我发现这第一次完美运行,但随后的尝试没有触发,因为TwoWay 绑定没有将我的属性设置回false

这是显示我的问题的简单项目:

MainWindow.xaml

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="100" Width="200">
    <ScrollViewer local:ScrollViewerBehavior.ScrollToTop="{Binding Reset, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="200"/>
            </Grid.RowDefinitions>
            <Button VerticalAlignment="Bottom" Content="Top" Command="{Binding Scroll}"/>
        </Grid>
    </ScrollViewer>
</Window>

MainWindow.xaml.cs

using System.Windows;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private ViewModel _ViewModel;

        public MainWindow()
        {
            InitializeComponent();

            DataContext = _ViewModel = new ViewModel();
        }
    }
}

ViewModel.cs

using System;
using System.ComponentModel;
using System.Windows.Input;

namespace WpfApp1
{
    public class RelayCommand : ICommand
    {
        private readonly Action<object> action;

        public RelayCommand(Action<object> action)
        {
            this.action = action;
        }

        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            action(parameter);
        }
    }

    public class ViewModel : INotifyPropertyChanged
    {
        private bool _reset = false;

        public ViewModel()
        {
            Scroll = new RelayCommand(o =>
            {
                Reset = true;
            });
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public bool Reset
        {
            get { return _reset; }
            set
            {
                bool changed = value != _reset;
                _reset = value;

                if (changed)
                {
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Reset)));
                }
            }
        }

        public RelayCommand Scroll { get; set; }
    }
}

ScrollViewerBehavior.cs

using System.Windows;
using System.Windows.Controls;

namespace WpfApp1
{
    public static class ScrollViewerBehavior
    {
        public static readonly DependencyProperty ScrollToTopProperty = DependencyProperty.RegisterAttached("ScrollToTop", typeof(bool), typeof(ScrollViewerBehavior), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, (o, e) =>
        {
            if (o is ScrollViewer sc)
            {
                if ((bool)e.NewValue)
                {
                    sc.ScrollToTop();
                    SetScrollToTop((FrameworkElement)o, false); // this should set the property back to false
                }
            }
        }));

        public static bool GetScrollToTop(FrameworkElement o)
        {
            return (bool)o.GetValue(ScrollToTopProperty);
        }

        public static void SetScrollToTop(FrameworkElement o, bool value)
        {
            o.SetValue(ScrollToTopProperty, value);
        }
    }
}

我知道,如果我取出更改后的房产支票,它会起作用;但是,这对我的情况并不理想。当我通过 WPF Inspector 查看元素时,我看到 ScrollViewer 上的属性应该是 false,但我的 ViewModel 属性仍然是 true

【问题讨论】:

  • debug找下来?
  • @ThierryV,我已经放了断点,当执行应该将值设置回 false 的代码行时,ViewModel 上没有任何内容。 WPF Inspector 说它已经更新,但我不确定还有什么要调试的。
  • 嗨,显然(我在这个问题上绊倒了几次)依赖属性的 Setvalue 方法不会触发 Notifypropertychanged 作为 expexted。也许使用 ' NotifyOnSourceUpdated=True , NotifyOnTargetUpdated=True' 扩展行为的绑定可能会有所帮助(尽管后者不会发生,因为您不会更改绑定控件上的值...)
  • 好的,重读节目,你需要更新目标 :)
  • @dba 知道它不会触发事件很有趣。有办法解决吗?

标签: c# wpf mvvm


【解决方案1】:

我的英语不好,但我写了这个例子。看看这个

[MainWindow.xaml.cs]

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    AnyClass c = new AnyClass();

    private void h1_Click(object sender, RoutedEventArgs e)
    {
        Test = true;
    }
    private void h2_Click(object sender, RoutedEventArgs e)
    {
        Test = false;
    }

    public bool Test
    {
        get { return (bool)GetValue(TestProperty); }
        set
        {
            SetValue(TestProperty, value);
            c.Val = value;
        }
    }
    public static readonly DependencyProperty TestProperty =
        DependencyProperty.Register("Test", typeof(bool), typeof(MainWindow), new PropertyMetadata(false));


}

[AnyClass.cs]
class AnyClass
{
    private bool val = false;
    public bool Val
    {
        get
        {
            return val;
        }
        set
        {
            val = value;
        }
    }
}

[mainWindow.xaml]
<Button Click="h1_Click" Content="true">
            <Button.Style>
                <Style TargetType="Button">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding ElementName=hUserControl, Path=Test}" Value="True">
                            <Setter Property="Visibility" Value="Collapsed"/>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding ElementName=hUserControl, Path=Test}" Value="False">
                            <Setter Property="Visibility" Value="Visible"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Button.Style>
        </Button>
        <Button Click="h2_Click" Content="false">
            <Button.Style>
                <Style TargetType="Button">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding ElementName=hUserControl, Path=Test}" Value="True">
                            <Setter Property="Visibility" Value="Visible"/>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding ElementName=hUserControl, Path=Test}" Value="False">
                            <Setter Property="Visibility" Value="Collapsed"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Button.Style>
        </Button>

【讨论】:

  • 你的例子并没有展示我想要做什么。问题是行为将值设置回 false,但 ViewModel 没有获得该值。
猜你喜欢
  • 1970-01-01
  • 2016-03-07
  • 1970-01-01
  • 2019-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多