【问题标题】:User control's Dependency Property doesn't get bound in Silverlight用户控件的依赖属性未在 Silverlight 中绑定
【发布时间】:2011-09-15 04:44:21
【问题描述】:

我已经创建了一个用户控件,如下所示的数字 updown

 <StackPanel Orientation="Horizontal" VerticalAlignment="Top" >
    <TextBox x:Name="InputTextBox" Grid.Row="0" Grid.Column="0" Grid.RowSpan="1"
                Style="{StaticResource NumericUpDownTextBoxStyle}"

             KeyDown="InputTextBox_KeyDown" 
             KeyUp="InputTextBox_KeyUp"
             GotFocus="InputTextBox_GotFocus" 
             LostFocus="InputTextBox_LostFocus"  
             MouseWheel="InputTextBox_MouseWheel"
             MouseEnter="InputTextBox_MouseEnter"
             LayoutUpdated="InputTextBox_LayoutUpdated" 
             Text="{Binding Path=ControlValue, Mode=TwoWay,ValidatesOnDataErrors=True,ValidatesOnExceptions=True,NotifyOnValidationError=True}"/>
</StackPanel>

我已将 ViewModel 绑定到此控件,我将 ControlValue 属性设置为用户控件模板文本框的 TextBox 属性。

在控制级别上一切正常。我已经从用户控制中暴露出来。

public static readonly DependencyProperty MaximumValueProperty;

public static readonly DependencyProperty MinimumValueProperty;

public static readonly DependencyProperty StepValueProperty;

public static readonly DependencyProperty TextValueProperty;

我的属性是

 public double Maximum
{
    get
    {
        return (double)GetValue(MaximumValueProperty);
    }
    set
    {
        SetValue(MaximumValueProperty, value);
        this.ViewModel.Maximum = this.Maximum;
    }
}

public double Minimum
{
    get
    {
        return (double)GetValue(MinimumValueProperty);
    }
    set
    {
        SetValue(MinimumValueProperty, value);
        this.ViewModel.Minimum = this.Minimum;
    }
}

public double Step
{
    get
    {
        return (double)GetValue(StepValueProperty);
    }
    set
    {
        SetValue(StepValueProperty, value);
        this.ViewModel.Step = this.Step;
    }
}

public double TextValue
{
    get
    {
        return (double)GetValue(TextValueProperty);
    }
    set
    {
        SetValue(TextValueProperty, value);
        this.ViewModel.ControlValue = Convert.ToString(value);
    }
}

属性的初始化。

  static NumericUpDown()
    {
        MaximumValueProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(null));
        MinimumValueProperty = DependencyProperty.Register("Minimum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(null));
        StepValueProperty = DependencyProperty.Register("Step", typeof(double), typeof(NumericUpDown), new PropertyMetadata(null));
        TextValueProperty = DependencyProperty.Register("TextValue", typeof(double), typeof(NumericUpDown), new PropertyMetadata(null));
    }

我在MainPage.xaml页面中的Usercontrol实现如下

 <local:NumericUpDown Maximum="28" Minimum="-28" Step="0.25" TextValue="{Binding ElementName=FranePrice, Path=DataContext.FranePrice}"></local:NumericUpDown>

我有另一个 ViewModel,我绑定到 XAML 页面,并且 ViewModel 中有一个属性,我绑定到 Usercontrol 的 TextValue 属性。

FramePrice 是视图模型中的属性,我绑定到用户控件的 TextValue 属性

主页 XAML 是

<UserControl x:Class="DatePicker.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"
xmlns:local="clr-namespace:DatePicker"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">

<Grid x:Name="LayoutRoot" Background="White">
    <StackPanel Orientation="Vertical">

        <local:NumericUpDown Maximum="28" Minimum="-28" Step="0.25" TextValue="{Binding ElementName=FranePrice, Path=DataContext.FranePrice}"></local:NumericUpDown>
        <Button Content="Show Date" Height="23" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click"/>
    </StackPanel>
</Grid>

我使用用户控件的页面的这个视图模型。在单击事件时,我向用户显示 TextValue。

公共类 MainPageViewModel : EntityViewModel {

    public MainPageViewModel()
    {

    }
    private double framePrice;
    public Double FramePrice
    {
        get
        {
            return framePrice;
        }
        set
        {
            framePrice = value;
            PropertyChangedHandler("FramePrice");
        }
    }
}

当我更改用户控件中的 TextValue 时,页面视图模型的 FramePrice 属性不会更改。

代码有什么问题吗????

根据 Luke Woodward 的帖子,我已将代码更新如下

 public static readonly DependencyProperty MaximumValueProperty;
    public static readonly DependencyProperty MinimumValueProperty;
    public static readonly DependencyProperty StepValueProperty;
    public static readonly DependencyProperty TextValueProperty;

    public static double Max;
    public static double Min;
    public static double Stp;
    public static double Val;

  public double Maximum
    {
        get
        {
            return (double)GetValue(MaximumValueProperty);
        }
        set
        {
            SetValue(MaximumValueProperty, value);
        }
    }

    public double Minimum
    {
        get
        {
            return (double)GetValue(MinimumValueProperty);
        }
        set
        {
            SetValue(MinimumValueProperty, value);
        }
    }

    public double Step
    {
        get
        {
            return (double)GetValue(StepValueProperty);
        }
        set
        {
            SetValue(StepValueProperty, value);
        }
    }

    public double TextValue
    {
        get
        {
            return (double)GetValue(TextValueProperty);
        }
        set
        {
            SetValue(TextValueProperty, value);
        }
    }
  static NumericUpDown()
    {
        MaximumValueProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(new PropertyChangedCallback(onMaximumValueChanged)));
        MinimumValueProperty = DependencyProperty.Register("Minimum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(new PropertyChangedCallback(onMinimumValueChanged)));
        StepValueProperty = DependencyProperty.Register("Step", typeof(double), typeof(NumericUpDown), new PropertyMetadata(new PropertyChangedCallback(onStepValueChanged)));
        TextValueProperty = DependencyProperty.Register("TextValue", typeof(double), typeof(NumericUpDown), new PropertyMetadata(new PropertyChangedCallback(onTextValueChanged)));
    }

    private static void onStepValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Stp = (double)e.NewValue;
    }
    private static void onMinimumValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Min = (double)e.NewValue;
    }
    private static void onMaximumValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Max = (double)e.NewValue;
    }
    private static void onTextValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Val = (double)e.NewValue;
    }

然后我在用户控件的视图模型中访问 Max、Min、Stp 和 Val 属性来执行我的逻辑。

XAML 代码如下

<local:NumericUpDown x:Name="ctlUpDown" Maximum="28" Minimum="-28" Step="0.25" TextValue="{Binding Path=FramePrice}"></local:NumericUpDown>

和用户控件的 XAML

<StackPanel Margin="5" Orientation="Horizontal" VerticalAlignment="Center">
    <TextBox x:Name="InputTextBox" Grid.Row="0" Grid.Column="0" Grid.RowSpan="1"
             Height="23" VerticalAlignment="Top" 
             Width="50" TextAlignment="Center"  
             KeyDown="InputTextBox_KeyDown" 
             KeyUp="InputTextBox_KeyUp"
             GotFocus="InputTextBox_GotFocus" 
             LostFocus="InputTextBox_LostFocus"  
             MouseWheel="InputTextBox_MouseWheel"
             MouseEnter="InputTextBox_MouseEnter"
             Text="{Binding Path=TextValue, ElementName=ctlUpDown,  Mode=TwoWay,ValidatesOnDataErrors=True,ValidatesOnExceptions=True,NotifyOnValidationError=True}"
             />
</StackPanel>

【问题讨论】:

  • 您的依赖属性不完整(例如,没有为初学者注册属性)并且您没有显示 FramePrice 代码。请用缺失的项目更新您的问题。
  • 我确实没有告诉你添加这些静态变量 MinMaxStpVal。他们不会做你想让他们做的事,因为他们是static,因此在所有 NumericUpDown 控件之间共享。它们是不正确的,你应该把它们全部去掉。您还把x:Name="ctlUpDown" 放在了错误的位置。您的 NumericUpDown.xaml 文件应以 &lt;UserControl x:Class="..." ... &gt; 元素开头,x:Name 位于该元素中,而不是 &lt;local:NumericUpDown ...&gt; 元素中。
  • @Luke WoodWard 我尝试了很多但无法解决它。我创建了一个相同的应用程序,请您通过它使其可行吗? 4shared.com/folder/KhfV9l-9/_online.html 这是链接。
  • -1 基本上放弃了提出问题并说“这是我的代码,请修复它”。
  • 我不相信你应该得到它(SO 上的大多数人不会这样做),但我仍然查看了你上传的两个项目之一并对其进行了一些更改让它达到我认为它做你想做的事的程度。请参阅我的更新答案。

标签: silverlight mvvm viewmodel


【解决方案1】:

我注意到您的代码有误的第一件事是属性MaximumMinimumStepTextValue。这是TextValue 属性:

public double TextValue
{
    get
    {
        return (double)GetValue(TextValueProperty);
    }
    set
    {
        SetValue(TextValueProperty, value);
        this.ViewModel.ControlValue = Convert.ToString(value);
    }
}

由依赖属性支持的属性,例如我上面提到的四个属性,应该始终如下所示:

public double TextValue
{
    get { return (double)GetValue(TextValueProperty); }
    set { SetValue(TextValueProperty, value); }
}

换句话说,getter 应该只包含对 GetValue 的调用,而 setter 应该只包含对 SetValue 的调用。

这样做的原因是当 Silverlight 更改 TextValue 依赖属性的值时,它不会通过使用上面的属性来做到这一点。依赖属性的值存储在 Silverlight 依赖系统中,当 Silverlight 想要更改其中一个属性的值时,它会直接进入此依赖系统。它根本不会调用您的代码。像上面这样的属性只是为了您的方便而提供,让您可以轻松地访问和更改存储在依赖属性中的值。除了您自己的代码之外,它们永远不会被其他任何东西调用。

一般来说,如果你想在依赖属性值改变时调用一个方法,你需要在注册依赖属性时在PropertyMetadata中传递一个PropertyChangedCallback。但是,我怀疑在您的情况下您不需要这样做。

在我看来,您具有三个属性:

  • 视图模型类中的 FramePrice 属性,
  • NumericUpDown 用户控件的 TextValue 依赖属性,
  • NumericUpDown 用户控件的 XAML 中 TextBox 的 Text 依赖属性。

我的印象是,您希望视图模型中的 FramePrice 属性始终与 TextBox 的 Text 属性具有相同的值。为此,您需要将 FramePrice 属性绑定到 NumericUpDown 的 TextValue 属性,然后将其绑定到 TextBox 的 Text 属性。

要将前两个属性绑定在一起,需要更改一些内容。首先,&lt;local:NumericUpDown&gt; 元素中的 TextValue 属性应如下所示

TextValue="{Binding Path=FramePrice}"

绑定{Binding ElementName=FramePrice, Path=DataContext.FramePrice} 将不起作用,因为您的XAML 中没有具有x:Name="FramePrice" 属性的元素。 {Binding ...}ElementName 属性的值必须与 XAML 中对象的 x:Name 匹配。

您还需要为您的主页设置 DataContext。如果您的主页视图模型对象具有零参数构造函数,则执行此操作的一种方法是遵循this answer

要将后两个属性绑定在一起,我会:

  • x:Name 属性添加到NumericUpDown 控件的&lt;UserControl&gt; 元素(例如x:Name="ctlUpDown"),
  • 将 NumericUpDown 控件中 TextBoxText 属性替换为以下内容:

    Text="{Binding Path=TextValue, ElementName=ctlUpDown, Mode=TwoWay, ValidatesOnDataErrors=True, ValidatesOnExceptions=True, NotifyOnValidationError=True}"/>
    

完成此操作后,您可以从代码隐藏类中删除所有行 this.ViewModel.SomeProperty = ...。它们不是必需的,正如我已经解释过的,它们不会在您希望它们运行时运行。

最后,您不使用 Silverlight Toolkit 的 NumericUpDown 控件是否有原因?

编辑 2:根据我的更好判断,我查看了您上传的两个 Silverlight 项目之一(我忽略了其中包含 _2 的项目)。它与您的问题几乎没有相似之处。

我只能假设您希望两个文本框(其中一个在用户控件中)始终具有相同的值。进行以下更改后,我能够做到这一点:

  • MainPageViewModel.cs:将ClearErrorFromProperty("DPropertyBind"); 添加到属性设置器。 (否则验证错误永远不会被清除。)

  • MyUserControlWVM.xaml:删除了对 LostFocus 事件处理程序的引用,添加了 Text 属性的绑定并将 x:Name 属性添加到 &lt;UserControl&gt; 元素。换句话说,它现在看起来像下面这样:

    <UserControl x:Class="DependencyPropertyBinding.MyUserControlWVM"
        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"
        x:Name="ctlWVM"
        d:DesignHeight="300" d:DesignWidth="205">
        <StackPanel Orientation="Horizontal" Width="204" Height="32">
            <TextBox x:Name="textbox" Height="30" Width="200" Text="{Binding Path=DProperty, ElementName=ctlWVM, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" />
        </StackPanel>
    </UserControl>
    
  • MyUserControlWVM.xaml.cs:将依赖属性DependencyPropertyValue 重命名为DPropertyProperty(命名约定是static readonly 字段具有属性的名称(在本例中为DProperty)和@987654354 @ 附加)。我还删除了TextBox_LostFocus 事件处理程序。

【讨论】:

  • 伍德沃德非常感谢您的指导。我在我的应用程序中发现了一些选项卡问题,我使用了近 15 个 NumericUpdown 控件。根据您的上述内容,我更改了代码,从 Setter 和 Getter 中删除了所有代码,并按照您的说明在 XAML 中完成了绑定,但我的 FramePrice 仍然没有通过用户控制进行更改。
  • 感谢您的回答我已完成更改并且工作正常。现在的问题是,当我在用户控件中不输入任何内容时,我应该在用户控件上获得验证通知。好像什么都不输入一样,我在主页的文本框中收到验证通知,因为它的属性与用户控件属性绑定。为什么我没有收到相同的通知???
【解决方案2】:

如果上面的代码是准确的,您在绑定中将 FramePrice 拼写为 FranePrice

当页面加载时,输出窗口应该将其显示为绑定错误。

目前是 Binding ElementName=FranePrice, Path=DataContext.FranePrice

应该是: Binding ElementName=FramePrice, Path=DataContext.FramePrice

“强大的绑定能力伴随着巨大的责任” :)

【讨论】:

  • 我已经更正了拼写,但我仍然在装订中遇到问题。
  • @HiTech:代码中有很多不一致和错误,我想你现在会在这里;)
  • 看看 ViewModel 被属性直接引用的方式,你不是在开玩笑。可能会运行一个工作版本只是为了它:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-24
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
  • 2016-01-07
相关资源
最近更新 更多