【问题标题】:Update of a Dependency Property when variable or field on which it depends on changes当依赖的变量或字段发生变化时更新依赖属性
【发布时间】:2011-07-16 08:09:39
【问题描述】:

我需要做的是?

我需要创建一个表达式依赖于哪个依赖属性。

假设如下:

Count = dependOne + dependTwo;

这里,Count依赖属性dependOnedependTwo是依赖属性Count应该依赖的两个变量。

现在,每当我更改变量 dependOnedependTwo 时,依赖属性都应该自动更新。

有可能吗?如果是那怎么办?

请看下面的代码

XAML:

<Window x:Class="DependecnyProperty.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBox Background="LightGray" Text="{Binding Path=Count}" Height="23" HorizontalAlignment="Left" Margin="164,102,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" />
        <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="164,148,0,0" Name="button1" VerticalAlignment="Top" Width="120" Click="button1_Click" />
    </Grid>
</Window>

代码隐藏:

namespace DependecnyProperty
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;

            Count = dependOne + dependTwo;
        }

        int dependOne = 0;
        int dependTwo = 0;

        public int Count
        {
            get { return (int)GetValue(CountProperty); }
            set { SetValue(CountProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Count.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CountProperty =
            DependencyProperty.Register("Count", typeof(int), typeof(MainWindow), new UIPropertyMetadata(12));

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            dependOne = dependOne + 2;
            dependTwo = dependTwo + 1;

            //I need to find way ...now here i have changed value of two variable.
            //now it is possible to change Dependency Property
            //Without here setting the value of dependency property
        }


    }
}

编辑更新后的代码隐藏:

namespace DependecnyProperty
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        ViewModel vm;
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;

            vm = new ViewModel();
            //this.DataContext = vm;
            Count = vm.DependOne + vm.DependTwo;
        }


        public int Count
        {
            get { return (int)GetValue(CountProperty); }
            set { SetValue(CountProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Count.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CountProperty =
            DependencyProperty.Register("Count", typeof(int), typeof(MainWindow), new UIPropertyMetadata(12));

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            vm.DependOne++;
            vm.DependTwo++;
            //I need to find way ...now here i have changed value of two variable.
            //now it is possible to change Dependency Property
            //Without here setting the value of dependency property

        }

        public class ViewModel : INotifyPropertyChanged
        {

            public ViewModel()
            {

            }

            private int dependOne;

            public int DependOne
            {
                get
                {
                    return dependOne;
                }
                set 
                { 
                    dependOne = value;
                    OnPropertyChanged("DependOne");
                }
            }

            private int dependTwo;

            public int DependTwo
            {
                get 
                { 
                    return dependTwo; 
                }
                set 
                { 
                    dependTwo = value;
                    OnPropertyChanged("DependTwo");
                }
            }

            #region --  INotifyPropertyChanged Members  --

            public event PropertyChangedEventHandler PropertyChanged;
            public void OnPropertyChanged(string propertyNameArg)
            {
                PropertyChangedEventHandler handler = this.PropertyChanged;

                if (handler != null)
                {
                    handler(this, new PropertyChangedEventArgs(propertyNameArg));
                }
            }
            #endregion
        }
    }
}

【问题讨论】:

    标签: c# .net wpf dependency-properties


    【解决方案1】:

    我不知道什么是最适合您的解决方案。但是,其中之一是您使用以下属性:

        //field
        private int _dependOne;
    
        //property
        public int DependOne
        {
            get { return _dependOne; }
            set {
                _dependOne = value;
                Count += value;
            }
        }
    
        //Finally, use the property instead of the field
        //dependOne = dependOne + 2;
        DependOne += 2;
    

    更新: 重要的是您不要在 Codebehind 中更新 ViewModel 属性。相反,您可以调用 ViewModel 方法。

    XAML

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Local="clr-namespace:WpfApplication1"
            Title="MainWindow" Height="350" Width="525">
    
        <StackPanel>
            <StackPanel.Resources>
                <Local:MyConverter x:Key="myConverter"/>
            </StackPanel.Resources>
            <TextBox>
                <TextBox.Text>
                    <MultiBinding Converter="{StaticResource myConverter}">
                        <Binding Path="DependOne" Mode="OneWay"/>
                        <Binding Path="DependTwo" Mode="OneWay"/>
                    </MultiBinding>
                </TextBox.Text>
            </TextBox>
            <Button Click="button1_Click">click</Button>
        </StackPanel>
    </Window>
    

    代码

    public partial class MainWindow : Window
    {
        ViewModel vm;
        public MainWindow()
        {
            InitializeComponent();
    
            vm = new ViewModel();
            this.DataContext = vm;
        }
    
    
        //public int Count
        //{
        //    get { return (int)GetValue(CountProperty); }
        //    set { SetValue(CountProperty, value); }
        //}
    
        //// Using a DependencyProperty as the backing store for Count.  This enables animation, styling, binding, etc...
        //public static readonly DependencyProperty CountProperty =
        //    DependencyProperty.Register("Count", typeof(int), typeof(MainWindow), new UIPropertyMetadata(12));
    
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            vm.UpdateCount();
        }
    
    
    }
    
    public class ViewModel : INotifyPropertyChanged
    {
    
        public ViewModel()
        {
    
        }
    
        private int dependOne = 0;
    
        public int DependOne
        {
            get
            {
                return dependOne;
            }
            set
            {
                dependOne = value;
                OnPropertyChanged("DependOne");
            }
        }
    
        private int dependTwo = 0;
    
        public int DependTwo
        {
            get
            {
                return dependTwo;
            }
            set
            {
                dependTwo = value;
                OnPropertyChanged("DependTwo");
            }
        }
    
        #region --  INotifyPropertyChanged Members  --
    
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propertyNameArg)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
    
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyNameArg));
            }
        }
        #endregion
    
        internal void UpdateCount()
        {
            DependOne = 3;
            DependTwo = 4;
        }
    }
    
    public class MyConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            var dependOne = (int)values[0];
            var dependTwo = (int)values[1];
    
            return (dependOne + dependTwo).ToString();
        }
    
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }
    

    【讨论】:

    • 是的,很简单...由于不了解您的实际情况,我只是这么说,但我认为@Merlyn Morgan-Graham 是好点。此外,如果dependOne 作用于View,您可以考虑将dependOne 设为DependecnyProperty。然后,使用Value Changed Callback 更新计数。
    • 感谢您的回答..但是..,根据格雷厄姆的回答.....我们必须在哪里表达...Count = dependOne + dependTwo;
    • 格雷厄姆的答案不是这个......您应该在 XAML 中使用将 Count 与dependOne 和dependTwo 绑定。
    • @Jung,, 使用 Mltibinding 还是其他方式?/
    • 当然需要MultibindingIMultiValueConverter
    【解决方案2】:

    我会:

    • dependOnedependTwo 放入视图模型中
    • INotifyPropertyChanged 添加到视图模型
    • 在调用这些属性的设置器时引发属性更改事件
    • 使用MultiBinding 将依赖属性绑定到这两个视图模型属性

    然后,每当这些属性被更新时,setter 就会自动被调用。

    此解决方案的另一个优点是您可以将计数器逻辑与依赖属性逻辑分开。它会更容易进行单元测试,并且可能更容易在不同的场景中重用。

    【讨论】:

    • @Graham,,,我很困惑Expression.....Count = dependOne + dependTwo;
    • @Aryan:你可以把它放在一个自定义的IMultiValueConverter 中,与MultiBinding 一起使用。
    • 我刚刚发布了代码,但想法的起源来自您的回答。
    【解决方案3】:

    Merlyn Morgan-Graham 的答案非常相似,您可以在 ViewModel 中引入另一个名为 Count 的只读属性。每当 DependOne 或 DependTwo 发生变化时引发 PropertyChanged("Count"),然后您可以对 Count 进行 OneWay 绑定

    private int m_dependOne;
    public int DependOne
    {
        get { return m_dependOne; }
        set
        {
            m_dependOne = value;
            OnPropertyChanged("DependOne");
            OnPropertyChanged("Count");
        }
    }
    
    private int m_dependTwo;
    public int DependTwo
    {
        get { return m_dependTwo; }
        set
        {
            m_dependTwo = value;
            OnPropertyChanged("DependTwo");
            OnPropertyChanged("Count");
        }
    }
    
    public int Count
    {
        get
        {
            return m_dependOne + m_dependTwo;
        }
    }
    

    那么绑定就这么简单

    <TextBlock Text="{Binding Count, Mode=OneWay}"/>
    

    【讨论】: