Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vb.net/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Wpf 处理用户控件';s DependencyProperty命令_Wpf_Vb.net_Wpf Controls_Dependency Properties_Icommand - Fatal编程技术网

Wpf 处理用户控件';s DependencyProperty命令

Wpf 处理用户控件';s DependencyProperty命令,wpf,vb.net,wpf-controls,dependency-properties,icommand,Wpf,Vb.net,Wpf Controls,Dependency Properties,Icommand,我正在努力让WPF UserControl在调用DependencyProperty命令时更新其一个DependencyProperty 这里有一个例子,希望能说明我正在努力实现的目标。基本上,它是一个带有按钮的用户控件。单击按钮时,我想使用命令(MyCommand)增加一个整数(MyValue): 用户控制 <UserControl x:Class="UserControl1" x:Name="root" xmlns="http://s

我正在努力让WPF UserControl在调用DependencyProperty命令时更新其一个DependencyProperty

这里有一个例子,希望能说明我正在努力实现的目标。基本上,它是一个带有按钮的用户控件。单击按钮时,我想使用命令(
MyCommand
)增加一个整数(
MyValue
):

用户控制

<UserControl x:Class="UserControl1"
             x:Name="root"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:WpfApp1"
             mc:Ignorable="d"
             d:DesignHeight="100"
             d:DesignWidth="200">

    <Button x:Name="MyButton"
            Content="{Binding MyValue, ElementName=root}"
            Command="{Binding MyCommand, ElementName=root}" />

</UserControl>
最后,我将此控件的5个实例添加到窗口中:

<Window x:Class="MainWindow"
        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:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow"
        Height="450"
        Width="800">
    <Grid>
        <StackPanel>
            <local:UserControl1 Width="40"
                                Height="40" />
            <local:UserControl1 Width="40"
                                Height="40" />
            <local:UserControl1 Width="40"
                                Height="40" />
            <local:UserControl1 Width="40"
                                Height="40" />
            <local:UserControl1 Width="40"
                                Height="40" />
        </StackPanel>
    </Grid>
</Window>
这很好,但我希望通过MyCommand绑定来处理这一问题,以尽量减少代码落后

我尝试过的另一种方法是创建命令(而不是作为dependencProperty):

RelayCommand
类未显示-它是委托命令的标准实现)

最后一种方法有效,但由于命令是共享的,因此会影响此用户控件的其他实例。例如,如果我有5个实例,单击第3个实例将增加XAML中前一个(第2个)实例的MyValue(而不是其他实例)

任何指点都将不胜感激


编辑1:继续使用非DP命令

按照@peter duniho的建议,我继续使用RelayCommand来处理按钮单击,但我没有运气让按钮调用未标记为共享的命令:

Public Class UserControl1
    Implements INotifyPropertyChanged

    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

    Public Shared ReadOnly ValueProperty As DependencyProperty = DependencyProperty.Register("MyValue", GetType(Integer), GetType(UserControl1), New PropertyMetadata(1))
    Private _localValue As Integer = 2

    Public Shared Property IncrementValueCommand As ICommand
    Public Shared Property IncrementLocalValueCommand As ICommand

    Public Sub New()

        ' This call is required by the designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        IncrementValueCommand = New RelayCommand(Sub() Value += 1)
        IncrementLocalValueCommand = New RelayCommand(Sub() LocalValue += 1)

    End Sub

    Public Property Value() As Integer
        Get
            Return GetValue(ValueProperty)
        End Get
        Set(value As Integer)
            SetValue(ValueProperty, value)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Value"))
        End Set
    End Property

    Public Property LocalValue() As Integer
        Get
            Return _localValue
        End Get
        Set(value As Integer)
            If _localValue <> value Then
                _localValue = value
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("LocalValue"))
            End If
        End Set
    End Property

End Class
这就是我坚持这种方法的地方。如果能向我解释这一点,我将不胜感激

至于创建一个视图模型来处理用户控件的逻辑,那就太好了,我没有这样做,因为从我所读到的来看,这是“代码臭味”,所以我试图远离这种方法

详细说明一下我的目标:我正在尝试制作一个标签用户控件,它可以显示两个向上/向下控件,一个用于小增量,另一个用于大增量。标签将具有许多其他功能,如:

  • 数据更改时闪烁
  • 支持“擦洗”(按住并移动鼠标以增加/减少值)
  • 具有可更改标签背景色的高亮显示特性

  • 视图模型方法似乎非常适合包含所有这些逻辑。

    您上次的尝试非常接近于可行的解决方案。如果您没有将该属性设置为
    共享的
    属性,那么它就会起作用。实际上,您甚至可以将
    RelayCommand
    实例分配给现有的
    MyCommand
    依赖属性,而不是创建新属性

    也就是说,目前还不清楚这种方法会给你带来什么好处。用户控件最终不会是通用的,您可以通过为
    按钮
    元素的
    单击
    事件实现更简单的事件处理程序来实现这种方法。所以,这里有一些关于你的问题和其中包含的代码的其他想法

    首先,WPF依赖项对象实现
    INotifyPropertyChanged
    是非常不寻常的,更不寻常的是,它实现其依赖项属性。如果您决定这样做,而不是像这里那样,通过从属性setter本身引发事件,那么您必须在注册依赖项属性时包含属性更改回调,如下所示:

    公共共享只读CommandProperty作为DependencyProperty=
    DependencyProperty.Register(“MyCommand”、GetType(ICommand)、GetType(UserControl1)、New PropertyMetadata(OnCommandPropertyChanged的地址))
    公共事件PropertyChanged为PropertyChangedEventHandler实现INotifyPropertyChanged.PropertyChanged
    Private Sub_RaisePropertyChanged(propertyName作为字符串)
    RaiseEvent PropertyChanged(Me,新PropertyChangedEventArgs(propertyName))
    端接头
    私有共享子OnCommandPropertyChanged(d作为DependencyObject,e作为DependencyPropertyChangedEventArgs)
    Dim userControl As UserControl1=CType(d,UserControl1)
    userControl.\u RaisePropertyChanged(e.Property.Name)
    端接头
    
    WPF绑定系统通常直接更新依赖项属性值,而无需通过属性设置器。在您发布的代码中,这意味着不会引发
    PropertyChanged
    事件,因为属性通过绑定更新。相反,您需要如上所述,以确保对属性的任何更改都将导致引发
    PropertyChanged
    事件

    也就是说,我建议不要为依赖项对象实现
    INotifyPropertyChanged
    。生成依赖项对象的场景通常与需要实现
    INotifyPropertyChanged
    的场景相互排斥,因为依赖项对象通常是绑定的目标,而
    INotifyPropertyChanged
    用于作为绑定源的对象。唯一需要观察绑定目标中属性值变化的组件是WPF绑定系统,它可以在依赖项对象未实现
    INotifyPropertyChanged
    的情况下完成这项工作

    其次,一种更惯用的实现方法是使用一个单独的视图模型对象来存储实际值和命令,并将该视图模型的属性绑定到依赖对象的属性。在这种情况下,视图模型对象的外观如下所示:

    导入System.ComponentModel
    导入System.Runtime.CompilerServices
    公共类UserControlViewModel
    实现INotifyPropertyChanged
    私有_值为整数
    公共属性值()为整数
    得到
    返回值
    结束
    设置(值为整数)
    _UpdatePropertyField(_值,value)
    端集
    端属性
    私人的_
    
    Private Sub HandleButtonClick() Handles MyButton.Click
        Value += 1
    End Sub
    
    Public Shared Property DirectCommand As ICommand
    
    Public Sub New()
    
        ' This call is required by the designer.
        InitializeComponent()
    
        ' Add any initialization after the InitializeComponent() call.
        DirectCommand = New RelayCommand(Sub() Value += 1)
    
    End Sub
    
    Public Class UserControl1
        Implements INotifyPropertyChanged
    
        Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    
        Public Shared ReadOnly ValueProperty As DependencyProperty = DependencyProperty.Register("MyValue", GetType(Integer), GetType(UserControl1), New PropertyMetadata(1))
        Private _localValue As Integer = 2
    
        Public Shared Property IncrementValueCommand As ICommand
        Public Shared Property IncrementLocalValueCommand As ICommand
    
        Public Sub New()
    
            ' This call is required by the designer.
            InitializeComponent()
    
            ' Add any initialization after the InitializeComponent() call.
            IncrementValueCommand = New RelayCommand(Sub() Value += 1)
            IncrementLocalValueCommand = New RelayCommand(Sub() LocalValue += 1)
    
        End Sub
    
        Public Property Value() As Integer
            Get
                Return GetValue(ValueProperty)
            End Get
            Set(value As Integer)
                SetValue(ValueProperty, value)
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Value"))
            End Set
        End Property
    
        Public Property LocalValue() As Integer
            Get
                Return _localValue
            End Get
            Set(value As Integer)
                If _localValue <> value Then
                    _localValue = value
                    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("LocalValue"))
                End If
            End Set
        End Property
    
    End Class
    
    <UserControl x:Class="UserControl1"
                 x:Name="root"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                 xmlns:local="clr-namespace:WpfApp1"
                 mc:Ignorable="d"
                 d:DesignHeight="100"
                 d:DesignWidth="200">
    
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="1*" />
                <RowDefinition Height="1*" />
            </Grid.RowDefinitions>
    
            <Button Grid.Row="0"
                    Background="DodgerBlue"
                    Content="{Binding Value, ElementName=root}"
                    Command="{Binding IncrementValueCommand, ElementName=root}" />
    
            <Button Grid.Row="1"
                    Background="Gold"
                    Content="{Binding LocalValue, ElementName=root}"
                    Command="{Binding IncrementLocalValueCommand, ElementName=root}" />
    
        </Grid>
    
    </UserControl>
    
    Public Property IncrementValueCommand As ICommand
    Public Property IncrementLocalValueCommand As ICommand