Обновление свойства зависимости, когда переменная или поле зависят от изменений - PullRequest
1 голос
/ 16 июля 2011

Что мне нужно сделать, это?

Мне нужно сделать одно выражение, от которого должно зависеть свойство зависимости.

Предположим, как указано ниже:

Count = dependOne + dependTwo;

Здесь Count равно Свойство зависимости , а dependOne и dependTwo - две переменные, от которых должно зависеть свойство зависимости Count.

Теперь всякий раз, когда я изменяю переменную dependOneили dependTwo свойство зависимости должно обновляться автоматически.

Возможно ли это?Если да, то как?

См. Код ниже

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 ]

3 голосов
/ 16 июля 2011

я бы:

  • Поместите dependOne и dependTwo в модель просмотра
  • Добавить INotifyPropertyChanged в модель просмотра
  • Вызывать событие изменения свойства, когда сеттеры этого свойства вызываются
  • Используйте MultiBinding , чтобы связать свойство зависимости с этими двумя свойствами модели представления

Тогда установщик будет автоматически вызываться при каждом обновлении этих свойств.

Еще одним преимуществом этого решения является то, что вы можете отделить логику счетчика от логики свойства зависимостей. Было бы проще провести модульное тестирование и, возможно, проще повторно использовать в различных сценариях.

3 голосов
/ 16 июля 2011

Я не знаю, какое для вас лучшее решение. Однако одним из них будет то, что вы используете 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;

ОБНОВЛЕНИЕ: Важно то, что вы не обновляете свойства ViewModel в Codebehind. Вместо этого вы можете вызвать метод ViewModel.

1010 * 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();
    }
}
2 голосов
/ 16 июля 2011

Очень похожий подход к ответу Мерлина Моргана-Грэма , вы можете ввести другое свойство readonly, называемое Count, в вашей ViewModel. Повышайте PropertyChanged ("Count") всякий раз, когда изменяется DependOne или DependTwo, тогда вы можете выполнить привязку OneWay к Count

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}"/>
...