Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.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 基于视图模型中的更改更新依赖项属性_Wpf_Mvvm_Viewmodel_Dependency Properties - Fatal编程技术网

Wpf 基于视图模型中的更改更新依赖项属性

Wpf 基于视图模型中的更改更新依赖项属性,wpf,mvvm,viewmodel,dependency-properties,Wpf,Mvvm,Viewmodel,Dependency Properties,我在WPF中的数据绑定方面遇到了一些问题。下面是一个场景:我制作了一个模拟拨号盘的用户控件(即,一个由12个按钮组成的数组,数字从“0”到“9”,再加上“#”和“清除”键)。该控件位于类库中,它是按照MVVM模式实现的,主要是因为我需要类库中的组件能够轻松地进行单元测试 控件的视图模型非常简单,每次用户按下拨号键按钮时,它基本上都会更新一个公共的“DialedNumber”字符串(该字符串在内部连接到该模型)。绑定工作正常,通过使用调试器,我可以确认viewmodel中的“DialledNumb

我在WPF中的数据绑定方面遇到了一些问题。下面是一个场景:我制作了一个模拟拨号盘的用户控件(即,一个由12个按钮组成的数组,数字从“0”到“9”,再加上“#”和“清除”键)。该控件位于类库中,它是按照MVVM模式实现的,主要是因为我需要类库中的组件能够轻松地进行单元测试

控件的视图模型非常简单,每次用户按下拨号键按钮时,它基本上都会更新一个公共的“DialedNumber”字符串(该字符串在内部连接到该模型)。绑定工作正常,通过使用调试器,我可以确认viewmodel中的“DialledNumber”变量在按下拨号板中的按钮时得到更新

这个拨号板控件由一个单独的XAML文件(Panel.XAML)使用,该文件列出了几个属于我的自定义类库的控件

现在,我想在面板文件中添加一个文本块,以便显示拨号板中的“DialledNumber”字符串。这是Panel.xaml中的代码段:

<PanelControls:DialPad x:Name="MyDialPad" DialedNumber="55325"/>
<TextBlock Text="{Binding ElementName=MyDialPad, Path=DialedNumber}" />
以下是拨号板视图模型:

public class DialPadViewModel : ObservableObject
{
    public DialPadViewModel()
    {
        _dialPadModel = new DialPadModel();
    }

    #region Fields

    private readonly DialPadModel _dialPadModel;
    private ICommand _dialPadKeyPressed;

    #endregion

    #region Public Properties/Command

    public DialPadModel DialPadModel
    {
        get { return _dialPadModel; }
    }

    public ICommand DialPadKeyPressedCommand
    {
        get
        {
            if (_dialPadKeyPressed == null)
            {
                _dialPadKeyPressed = new RelayCommand(DialPadKeyPressedCmd);
            }
            return _dialPadKeyPressed;
        }
    }

    public string DialedNumber
    {
        get { return _dialPadModel.DialedNumber; }
        set
        {
            _dialPadModel.DialedNumber = value;
            RaisePropertyChanged("DialedNumber");
        }
    }

    #endregion

    #region Private Helpers

    private void DialPadKeyPressedCmd(object parameter)
    {
        string keyPressedString = parameter.ToString();

        if (keyPressedString.Length > 0)
        {
            if (char.IsDigit(keyPressedString[0]))
            {
                DialedNumber += keyPressedString[0].ToString(CultureInfo.InvariantCulture);
            }
            else if (keyPressedString == "C" || keyPressedString == "Clr" || keyPressedString == "Clear")
            {
                DialedNumber = "";
            }
        }
    }

    #endregion
}

让我重申一下我的问题:Panel.xaml中的textblock在开始时显示正确的数字(55325),但当我按下拨号键时,它的值永远不会更新。我在DialPadKeyPressedCmd中放置了一个断点,我可以确认每次我在拨号板中按一个键时都会执行该方法。

听起来您可以向视图中添加一个文本框,并将其文本属性绑定到视图模型的DialedNumber属性

 <TextBox Text="{Binding Path=DialedNumber}"></TextBox>

如果我误解了您的问题,请告诉我。

如果您将拨号板放在视图中,您可以在ViewModel中创建DialPadViewModel属性(公共+全局):

public DialPadViewModel DialPadViewModel = new DialPadViewModel();
<TextBox Text="{Binding Path=DialPadViewModel.DialedNumber}"/>
现在将视图的DataContext绑定设置为ViewModel,并将拨号盘DataContext也绑定到它,如

<local:DialPad DataContext="{Binding}"/>
编辑2:我发现了问题:

在DialPad.xaml中,您的所有命令都从参考资料绑定到DialPadViewModel,而TextBloc绑定到DialPads DataContext,后者是DialPadViewModel的另一个实例


因此,每次点击拨号板按钮时,您都会更改资源的DPVM实例中的DialledNumber值,而不是DataContext的DPVM实例中的DialledNumber值。

DependencyProperties用于指向其他一些属性以获取其值。因此,您可以将它指向您的
DialPadViewModel.DialedNumber
,也可以在使用UserControl时将它指向其他字符串(绑定或硬编码值,如“551”),但不能同时执行这两项操作

在您的情况下,当有人绑定到
dialledNumber
依赖项属性时,他们将用新值替换当前值(绑定到
DialPadViewModel.dialledNumber

根据您的代码外观和您想做什么,有几种方法可以解决这个问题

首先,您可以坚持希望使用您的控件的人也使用您的ViewModel,并且不要将
DialledNumber
作为公共依赖属性

因此,我们不允许创建一个具有
someotherdialledNumber
属性和绑定的自定义类

<DialPad DialedNumber="{Binding SomeOtherDialedNumber}">
我能想到的另一种选择是将DependencyProperty与ViewModel属性以及一些PropertyChange通知同步

您需要随时更新
DialPadViewModel.DialedNumber
依赖项属性更改(您可能需要用于属性更改通知),您还必须编写一些内容来随时更新
dialledNumber
依赖项属性的源
DialPadViewModel.dialledNumber
更改

就个人而言,如果我的UserControl有一个ViewModel,那么我使用第一个选项。如果没有,我将完全摆脱ViewModel,并在代码隐藏中为UserControl构建逻辑,而不使用ViewModel


原因是WPF使用两层:UI层和数据层。
DataContext
是数据层,而ViewModel通常是数据层的一部分。通过在UserControl的构造函数中显式设置数据层(
DataContext
),您将数据层与UI层相结合,这与使用MVVM的最大原因之一:关注点分离背道而驰。UserControl实际上应该只是一个漂亮的shell,您应该能够将其放置在任何数据层的顶部。

尝试将Source设置为Source=DialPadViewModel……因为您是通过路径指定DialedNumber属性。@colinsmith:我试过了,但运气不好。绑定到按钮的命令将被调用,viewmodel/model将被更新,但视图中的dependency属性未获得新值。感谢您的回复!在回答的某个时候,您说“并且您还必须编写一些内容,以便在DialPadViewModel.DialedNumber发生更改时更新DialedNumber依赖项属性的源。”。这正是我需要实现的,但我不知道如何实现。我已经知道如何将从DialledNumber到DialPadViewModel.DialledNumber的更改进行通信,但我不知道如何以另一种方式进行通信。如何根据viewmodel中的状态更改更新视图?谢谢您的回复!是的,我这样做了,但我的问题是有一点移动涉及。基本上,每次我按下拨号板按钮时,我的viewmodel都会更新,但我不知道如何将更新后的状态信息提供给视图。这应该可以工作。确保视图控件的绑定模式为双向…模式=双向。此外,您将在DialledNumber属性中从模型返回值。确保它有价值。我试过了,但没用。我想我的问题可以归结为如何在拨号号码loca中输入更新
<TextBox Text="{Binding Path=DialPadViewModel.DialedNumber}"/>
public string DialedNumber
{
    get
    {
        return DialPadViewModel.DialedNumber;
    }
    set
    {
        DialPadViewModel.DialedNumber = value;
    }
}
<DialPad DialedNumber="{Binding SomeOtherDialedNumber}">
<DataTemplate DataType="{x:Type DialPadViewModel}">
    <local:DialPad />
</DataTemplate>