在依赖于更改的变量或字段时更新依赖项属性

时间:2011-07-16 08:09:39

标签: c# .net wpf dependency-properties

我需要做的是什么?

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

假设如下:

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
        }
    }
}

3 个答案:

答案 0 :(得分:3)

我不知道什么是最适合你的解决方案。然而,其中之一就是你使用Property:

    //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>

<强> CODE

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();
    }
}

答案 1 :(得分:3)

我最好:

  • dependOnedependTwo放入视图模型
  • INotifyPropertyChanged添加到视图模型
  • 当这些属性的setter被调用时,提升属性更改事件
  • 使用MultiBinding将依赖项属性绑定到这两个视图模型属性

然后,只要更新了这些属性,就会自动调用setter。

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

答案 2 :(得分:2)

Merlyn Morgan-Graham 的答案非常类似,您可以在ViewModel中引入另一个名为Count的readonly属性。每当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}"/>