简体   繁体   English

TwoWay绑定未更新

[英]TwoWay Binding Not Updating

I've added a ScrollViewer behavior that allows me to scroll to the top when a property is set to true based on Scroll the scrollviewer to top through viewmodel . 我添加了ScrollViewer行为,当基于ScrollScroller通过viewmodel滚动到顶部时,当属性设置为true时,我可以滚动到顶部。 I've found that this works perfectly the first time, but subsequent attempts do not fire because the TwoWay binding isn't setting my property back to false . 我发现这第一次很好,但是随后的尝试不会触发,因为TwoWay绑定没有将我的属性设置为false

Here is my simple project showing my issue: 这是显示我的问题的简单项目:

MainWindow.xaml 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 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 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 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);
        }
    }
}

I know that if I take out the changed check on the property, it works; 我知道,如果我拿出财产的变更支票,它就可以工作; however, that is not ideal for my situation. 但是,这对于我的情况而言并不理想。 When I look at the element through WPF Inspector, I see that the property on the ScrollViewer is false as it should be, but my ViewModel property remains true . 当我通过WPF检查器查看元素时,我看到ScrollViewer上的属性应该是false ,但我的ViewModel属性仍然为true

I'm not good in English but i wrote this example. 我英语不好,但是我写了这个例子。 Look at this 看这个

[MainWindow.xaml.cs] [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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM