如何在Silverlight中正确通知将一个自定义属性从另一个属性绑定到不同的控件?

时间:2013-12-09 17:13:19

标签: c# silverlight

我有这个MainPage.xaml:

<UserControl x:Class="SilverlightApplication2.MainPage"
    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"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400" Height="246" Width="562">

        <Grid HorizontalAlignment="Left" Width="552" ShowGridLines="True" VerticalAlignment="Top">
            <Grid.ColumnDefinitions>
            <ColumnDefinition Width="275" />
                <ColumnDefinition Width="113"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="45" />
                <RowDefinition Height="45" />
                <RowDefinition Height="45" />
                <RowDefinition Height="45" />
                <RowDefinition Height="45" />
            </Grid.RowDefinitions>
        <Slider x:Name="sliderLoanAmount" Value="{Binding LoanAmount, Mode=TwoWay}" Height="35" SmallChange="1" LargeChange="10000" Minimum="0" Maximum="700000" HorizontalAlignment="Left" VerticalAlignment="Center" Width="265" Margin="0" TabIndex="1" />
        <TextBox Grid.Column="1" x:Name="textLoanAmount" Text="{Binding LoanAmount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="70" VerticalAlignment="Center" Margin="0,12" Foreground="Blue" FontSize="14" FontStretch="Normal" TextAlignment="Left" FontWeight="Bold" Padding="0" TabIndex="2" />

        <Slider x:Name="sliderDownPaymentPercent" Value="{Binding DownPaymentPercent, Mode=TwoWay}" SmallChange="1" LargeChange="10" Minimum="0" Maximum="100" HorizontalAlignment="Left" Width="265" Height="35" VerticalAlignment="Center" Margin="0" Grid.Row="1" TabIndex="3" />
        <TextBox Grid.Row="1" Grid.Column="1" x:Name="textDownPaymentAmount" Text="{Binding DownPaymentAmount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="70" VerticalAlignment="Center" Margin="0,12" Foreground="Blue" FontSize="14" FontStretch="Normal" TextAlignment="Left" FontWeight="Bold" Padding="0" TabIndex="3" />

        </Grid>
</UserControl>

此外,我还有自定义LoanData类,其属性绑定到滑块和文本框控件:

public partial class MainPage : UserControl
{
    private LoanData Loan
    {
        get;
        set;
    }

    public MainPage()
    {
        InitializeComponent();

        this.Loan = new LoanData { LoanAmount = 700000, DownPaymentPercent = 20, DownPaymentAmount = 140000};
        this.DataContext = this.Loan;
    }
}

public class LoanData : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    private long _LoanAmount;
    public long LoanAmount
    {
        get { return _LoanAmount; }
        set
        {
            if (_LoanAmount != value)
            {
                _LoanAmount = value;
                NotifyPropertyChanged("LoanAmount");
            }
        }
    }

    private long _DownPaymentPercent;
    public long DownPaymentPercent
    {
        get { return _DownPaymentPercent; }
        set
        {
            if (_DownPaymentPercent != value)
            {
                _DownPaymentPercent = value;
                NotifyPropertyChanged("DownPaymentPercent");

                DownPaymentAmount = DownPaymentAmount;
                //NotifyPropertyChanged("DownPaymentAmount");
            }
            else
            {
                if (LoanAmount != 0)
                {
                    _DownPaymentPercent = (DownPaymentAmount / LoanAmount) * 100;
                    NotifyPropertyChanged("DownPaymentPercent");
                }
            }
        }
    }

    private long _DownPaymentAmount;
    public long DownPaymentAmount
    {
        get { return _DownPaymentAmount; }
        set
        {
            if (_DownPaymentAmount != value)
            {
                _DownPaymentAmount = value;
                NotifyPropertyChanged("DownPaymentAmount");

                DownPaymentPercent = DownPaymentPercent;
                //NotifyPropertyChanged("DownPaymentPercent");
            }
            else
            {
                _DownPaymentAmount = (DownPaymentPercent * LoanAmount) / 100;
                NotifyPropertyChanged("DownPaymentAmount");
            }
        }
    }

}

控制sliderLoanAmount和textLoanAmount绑定到LoanAmount属性。更改滑块位置会导致文本值发生变化,反之亦然。

但我需要更复杂的逻辑来实现下两个控件。 当我重新定位sliderDownPaymentPercent控件时,textDownPaymentAmount值必须是DownPaymentAmount =(DownPaymentPercent * LoanAmount)/ 100。 当我在textDownPaymentAmount控件中更改值时,sliderDownPaymentPercent必须重新定位到值DownPaymentPercent =(DownPaymentAmount / LoanAmount)* 100.

当我重新定位sliderDownPaymentPercent时,执行以下代码:

if (_DownPaymentPercent != value)
{
    _DownPaymentPercent = value;
    NotifyPropertyChanged("DownPaymentPercent");

    DownPaymentAmount = DownPaymentAmount;
    //NotifyPropertyChanged("DownPaymentAmount");
}

我想通过调用

告诉textDownPaymentAmount更改其值
NotifyPropertyChanged("DownPaymentAmount");

但它找不到工作和唯一的解决方案:

 DownPaymentAmount = DownPaymentAmount;

这导致执行此代码:

else
{
    _DownPaymentAmount = (DownPaymentPercent * LoanAmount) / 100;
    NotifyPropertyChanged("DownPaymentAmount");
}

当我输入textDownPaymentAmount时执行代码:

if (_DownPaymentAmount != value)
{
    _DownPaymentAmount = value;
    NotifyPropertyChanged("DownPaymentAmount");

    DownPaymentPercent = DownPaymentPercent;
    //NotifyPropertyChanged("DownPaymentPercent");
}

如您所见,我必须再次打电话

DownPaymentPercent = DownPaymentPercent;

代替

 //NotifyPropertyChanged("DownPaymentPercent");

所以我的问题是如何正确通知从另一个属性更改一个属性 用这个:

DownPaymentPercent = DownPaymentPercent;

OR

DownPaymentAmount = DownPaymentAmount;

2 个答案:

答案 0 :(得分:0)

我认为问题是你的属性使用long类型,而滑块值必须是double类型。

试试这个:

    <Slider x:Name="sliderLoanAmount" Value="{Binding LoanAmount, Mode=TwoWay}" Height="35" SmallChange="1" LargeChange="10000" Minimum="0" Maximum="700000" HorizontalAlignment="Left" VerticalAlignment="Center" Width="265" Margin="0" TabIndex="1" />
    <TextBox Grid.Column="1" x:Name="textLoanAmount" Text="{Binding LoanAmount, Mode=TwoWay}" Width="70" VerticalAlignment="Center" Margin="0,12" Foreground="Blue" FontSize="14" FontStretch="Normal" TextAlignment="Left" FontWeight="Bold" Padding="0" TabIndex="2" />

    <Slider x:Name="sliderDownPaymentPercent" Value="{Binding DownPaymentPercent, Mode=TwoWay}" SmallChange="1" LargeChange="10" Minimum="0" Maximum="100" HorizontalAlignment="Left" Width="265" Height="35" VerticalAlignment="Center" Margin="0" Grid.Row="1" TabIndex="3" />
    <TextBox Grid.Row="1" Grid.Column="1" x:Name="textDownPaymentAmount" Text="{Binding DownPaymentAmount, Mode=TwoWay}" Width="70" VerticalAlignment="Center" Margin="0,12" Foreground="Blue" FontSize="14" FontStretch="Normal" TextAlignment="Left" FontWeight="Bold" Padding="0" TabIndex="3" />

public class LoanData : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    private double _LoanAmount;
    public double LoanAmount
    {
        get { return _LoanAmount; }
        set
        {
            if (_LoanAmount != value)
            {
                _LoanAmount = value;
                NotifyPropertyChanged("LoanAmount");
                DownPaymentAmount = (DownPaymentPercent / 100) * LoanAmount;
            }
        }
    }

    private double _DownPaymentPercent;
    public double DownPaymentPercent
    {
        get { return _DownPaymentPercent; }
        set
        {
            if (_DownPaymentPercent != value)
            {
                _DownPaymentPercent = value;
                NotifyPropertyChanged("DownPaymentPercent");
                DownPaymentAmount = (DownPaymentPercent / 100) * LoanAmount;
            }
        }
    }

    private double _DownPaymentAmount;
    public double DownPaymentAmount
    {
        get { return _DownPaymentAmount; }
        set
        {
            if (_DownPaymentAmount != value)
            {
                _DownPaymentAmount = value;
                NotifyPropertyChanged("DownPaymentAmount");
                DownPaymentPercent = (DownPaymentAmount / LoanAmount) * 100;
            }
        }
    }

}

答案 1 :(得分:0)

我想我在这里看到了问题: 在DownPaymentPercent和DownPaymentAmount的设置器中,您都需要重新计算支持字段_DownPaymentPercent resp。只要“new”值与“old”值相同,_DownPaymentAmount。 见:

if (_DownPaymentAmount != value)
{
   /*snip*/
}
else
{
    _DownPaymentAmount = (DownPaymentPercent * LoanAmount) / 100;
    NotifyPropertyChanged("DownPaymentAmount");
}

这意味着您的语句DownPaymentPercent = DownPaymentPercent;实际上更改了DownPaymentPercent的值(并触发NotifyPropertyChanged)。 所以NotifyPropertyChanged的(现已注释掉)调用实际上有效,但是唉!支持字段的值仍然是旧值(没有重新计算,绑定实际更新但您在UI中看不到任何更改,因为您的DataContext提供了已显示的相同值)。 要解决此问题,每次使用新值调用其中一个setter时,必须重新计算其他相关值:

//setter for DownPaymentAmount...
set
{
    if (_DownPaymentAmount != value)
    {
        _DownPaymentAmount = value;
        NotifyPropertyChanged("DownPaymentAmount");

        //recalculate dependent property backing field
        if (LoanAmount != 0)
        {
            _DownPaymentPercent = (DownPaymentAmount / LoanAmount) * 100;
            NotifyPropertyChanged("DownPaymentPercent");
        }
    }
}

//...and setter for DownPaymentPercent
set
{
    if (_DownPaymentPercent != value)
    {
        _DownPaymentPercent = value;
        NotifyPropertyChanged("DownPaymentPercent");

        //recalculate dependent property backing field
        _DownPaymentAmount = (DownPaymentPercent * LoanAmount) / 100;
        NotifyPropertyChanged("DownPaymentAmount");
    }
}

[编辑]由于整数运算,您的语句_DownPaymentPercent = (DownPaymentAmount / LoanAmount) * 100;很可能会导致_DownPaymentPercent变为0。 DownPaymentAmount / LoanAmount结果为0,将0与100相乘仍为0。