TextBlock不使用ViewModel进行更新 [英] TextBlock not updating using ViewModel

查看:80
本文介绍了TextBlock不使用ViewModel进行更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有TextBlock的WPF窗口(MainWindow.xaml),它显示来自其他UserControl(SampleUserControl.xaml)的结果。我将一个String值(你选择颜色红色。)传递给我的ViewModel(ColorVM.vb)来更新我的WPF窗口中的TextBlock。问题是TextBlock不显示我的UserControl的值。以下是我的示例VB WPF项目的代码:



MainWindow.xaml

 <  窗口    x:类  =  MainWindow  

xmlns = http://schemas.microsoft.com/winfx/2006/xaml/presentation

xmlns:x = http://schemas.microsoft.com / winfx / 2006 / xaml

标题 = Window1 高度 = 300 宽度 = 300 >
< 网格 >
< TextBlock x:名称 = StatusIndicatorTextBlock 文字 = {绑定MainWindowStatusIndicator } / >
< / Grid >
< / Window >





SampleUserControl.xaml

 <  < span class =code-leadattribute> UserControl     x:Class   =  SampleUserControl  

xmlns = http://schemas.microsoft.com/winfx/2006/xaml/presentation

< span class =code-attribute> 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

mc:可忽略 = d

d:DesignHeight = 300 < span class =code-attribute> d:DesignWidth = 300 >
< 网格 >
< < span class =code-leadattribute>按钮 x:名称 = Button1 点击 = Button1_Click / >
< / Grid >
< / UserControl >





ColorVM.vb

  Imports  System.ComponentModel 

公共 ColorVM
实现 INotifyPropertyChanged

私有 _Results 作为 字符串

公共 Sub ()
._ Results = _Results
结束 Sub

公开 属性结果作为 字符串
获取
返回 ._结果
结束 获取

设置 ByVal ResultsValue As String
Me ._ Results = ResultsValue
Me .NotifyPropertyChanged( MainWindowStatusIndicator
结束 设置
结束 属性

公开 事件 PropertyChanged(发件人作为 对象,e 作为 PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged

私有 Sub NotifyPropertyChanged( ByVal propertyName 作为 字符串
RaiseEvent PropertyChanged( Me PropertyChangedEventArgs (propertyName))
结束 Sub
结束





SampleUserControl.vb

 公共  SampleUserControl 

私有 Sub Button1_Click(发件人 As 对象,e As RoutedEventArgs)句柄 Button1.Click
Dim ColorVM As New ColorVM()
颜色VM.Results = 您选择红色。
结束 Sub
结束 班级





希望你能解决我的问题,因为我是WPF开发的新手:)

解决方案

第一个问题



您绑定到名为 MainWindowStatusIndicator <的属性/ code>;你为一个名为 MainWindowStatusIndicator 的属性提出 PropertyChanged 事件但你的属性实际上称为结果



如果查看调试在Visual Studio中输出窗口,您将看到绑定错误,告诉您viewmodel不包含名为 MainWindowStatusIndicator 的属性。



将属性名称更改为 MainWindowStatusIndicator ,或更改 NotifyPropertyChanged 调用正确的属性名称。



第二个问题



你的 Button1_Click 方法创建一个viewmodel类的新实例,在该新实例上设置一个属性,然后抛出它。



更改为类的一个实例上的实例属性不会影响该类的任何其他实例。



您有两种选择:



  1. 从控件的中检索viewmodel类的当前实例DataContext 属性,并更改该实例上的属性:

     私有  Sub  Button1_Click(发件人作为 对象, e  As  RoutedEventArgs)句柄 Button1.Click 
    Dim context As ColorVM = TryCast (DataContext,ColorVM)
    如果 context IsNot Nothing 然后
    context.MainWindowStatusIndicator = ...
    结束 如果
    结束 Sub

  2. 以MVVM方式执行 - 删除click事件处理程序,并使用 ICommand 相反:



    你需要一个 ICommand 实现,它会在你的viewmodel上调用一个函数。有多种选择 - 这只是Google搜索中的随机选项:

     ' 来自以下博文的代码: 
    ' http://www.paulspatterson.com/mvvm-and-wpf-for-vb-net-%E2%80%93-part-5-%E2%80%93-delegating-commands/
    ' 如果您有自己的版本,请随意使用。 :)
    公共 DelegateCommand: Implements ICommand
    Private m_canExecute As Func( Of Object Boolean
    私有 m_executeAction 作为操作( 对象
    私有 m_canExecuteCache 作为 Boolean

    公共 事件 CanExecuteChanged( ByVal 发​​件人作为 对象 ByVal e As System.EventArgs) Implements ICommand.CanExecuteChanged

    公开 Sub ByVal executeAction 作为动作( 对象), ByVal canExecute As Func( 对象布尔))
    .m_executeAction = executeAction
    .m_canExecute = canExecute
    结束 Sub

    公共 功能该ion CanExecute( ByVal 参数作为 对象作为 布尔 实施 ICommand .CanExecute
    Dim temp As Boolean = m_canExecute(parameter)
    如果 m_canExecuteCache<> temp 然后
    m_canExecuteCache = temp
    RaiseEvent CanExecuteChanged( EventArgs())
    结束 如果
    返回 m_canExecuteCache
    结束 功能

    公开 Sub 执行( ByVal 参数作为 对象实现 ICommand.Execute
    m_executeAction(参数)
    结束 < span class =code-keyword> Sub
    结束





    您的viewmodel然后公开 ICommand 实现的属性,调用viewmodel上的私有方法,以便在单击按钮时执行操作:

     公共 < span class =code-keyword> Class  ColorVM: Implements  INotifyPropertyChanged 

    私有 _MainWindowStatusIndicator 作为 字符串
    私人 _ChooseColorCommand 作为 ICommand

    公共 Sub New ()
    Me ._ ChooseColorCommand = < span class =code-keyword>新 DelegateCommand( AddressOf ChooseColo r, AddressOf CanChooseColor)
    结束 Sub

    公开 ReadOnly 属性 ChooseColorCommand 作为 ICommand
    获取
    返回 _ChooseColorCommand
    结束 获取
    结束 属性

    公共 属性 MainWindowStatusIndicator 作为 字符串
    获取
    返回 _MainWindowStatusInd icator
    结束 获取
    设置 ByVal 作为 字符串
    _MainWindowStatusIndicator = Value
    NotifyPropertyChanged( MainWindowStatusIndicator
    结束 设置
    结束 属性

    公共 事件 PropertyChanged(发件人作为 对象,e 作为 PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged

    私有 Sub NotifyPropertyChanged( ByVal propertyName < span class =code-keyword> As String
    RaiseEvent PropertyChanged ( Me PropertyChangedEventArgs(propertyName))
    结束 Sub

    私有 Sub ChooseColor(param As Object
    MainWindowStatusIndicator = < span class =code-string> ...
    结束 Sub

    私人 乐趣ction CanChooseColor(param As Object As 布尔
    返回 True
    结束 功能
    结束





    您的XAML然后绑定到 ICommand 实施,并且根本不使用点击事件:

     <   UserControl     x:Class   =  SampleUserControl  

    < span class =code-attribute> 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

    mc:可忽略 = d

    d:DesignHeight = 300 d:DesignWidth = 300

    >
    < 网格 >
    < 按钮 x:名称 = Button1 命令 = {绑定路径= ChooseColorCommand} / >
    < / Grid >
    < / UserControl >


I have a WPF Window (MainWindow.xaml) with TextBlock that displays the result from other UserControl (SampleUserControl.xaml). I pass a String value ("You choose color Red.") to my ViewModel (ColorVM.vb) to update my TextBlock in my WPF Window. The problem is that the TextBlock does not display the value from my UserControl. Here is the code of my sample VB WPF project:

MainWindow.xaml

<Window x:Class="MainWindow"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Window1" Height="300" Width="300">
    <Grid>        
        <TextBlock x:Name="StatusIndicatorTextBlock" Text="{Binding MainWindowStatusIndicator}"/>
    </Grid>
</Window>



SampleUserControl.xaml

<UserControl x:Class="SampleUserControl"

             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" 

             mc:Ignorable="d" 

             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
            <Button x:Name="Button1" Click="Button1_Click"/>
    </Grid>
</UserControl>



ColorVM.vb

Imports System.ComponentModel

Public Class ColorVM
    Implements INotifyPropertyChanged

    Private _Results As String

    Public Sub New()
        Me._Results = _Results 
    End Sub

    Public Property Results As String
        Get
            Return Me._Results 
        End Get

        Set(ByVal ResultsValue As String)
            Me._Results = ResultsValue 
            Me.NotifyPropertyChanged("MainWindowStatusIndicator")
        End Set
    End Property
    
    Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged

    Private Sub NotifyPropertyChanged(ByVal propertyName As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    End Sub
End Class



SampleUserControl.vb

Public Class SampleUserControl

    Private Sub Button1_Click(sender As Object, e As RoutedEventArgs) Handles Button1.Click
        Dim ColorVM As New ColorVM()
        ColorVM.Results = "You choose color Red."
    End Sub
End Class



Hope that you can help me in my problem because I'm a newbie in WPF development :)

解决方案

First Problem


You're binding to a property called MainWindowStatusIndicator; you're raising a PropertyChanged event for a property called MainWindowStatusIndicator; but your property is actually called Results.

If you look in the debug output window in Visual Studio, you'll see binding errors telling you that your viewmodel doesn't contain a property called MainWindowStatusIndicator.

Either change the name of the property to MainWindowStatusIndicator, or change the binding and the string in the NotifyPropertyChanged call to the correct property name.

Second Problem


Your Button1_Click method creates a new instance of your viewmodel class, sets a property on that new instance, and then throws it away.

A change to an instance property on one instance of a class will not affect any other instance of that class.

You have two options:


  1. Retrieve the current instance of the viewmodel class from the control's DataContext property, and change the property on that instance:

    Private Sub Button1_Click(sender As Object, e As RoutedEventArgs) Handles Button1.Click
        Dim context As ColorVM = TryCast(DataContext, ColorVM)
        If context IsNot Nothing Then
            context.MainWindowStatusIndicator = "..."
        End If
    End Sub

  2. Do it the MVVM way - remove the click event handler, and use an ICommand instead:

    You'll need an ICommand implementation which calls a function on your viewmodel. There are various options available - this is just a random one from a Google search:

    ' Code from the following blog post:
    ' http://www.paulspatterson.com/mvvm-and-wpf-for-vb-net-%E2%80%93-part-5-%E2%80%93-delegating-commands/
    ' Feel free to use your own version if you have one. :)
    Public Class DelegateCommand : Implements ICommand
        Private m_canExecute As Func(Of Object, Boolean)
        Private m_executeAction As Action(Of Object)
        Private m_canExecuteCache As Boolean
    
        Public Event CanExecuteChanged(ByVal sender As Object, ByVal e As System.EventArgs) Implements ICommand.CanExecuteChanged
    
        Public Sub New(ByVal executeAction As Action(Of Object), ByVal canExecute As Func(Of Object, Boolean))
            Me.m_executeAction = executeAction
            Me.m_canExecute = canExecute
        End Sub
    
        Public Function CanExecute(ByVal parameter As Object) As Boolean Implements ICommand.CanExecute
            Dim temp As Boolean = m_canExecute(parameter)
            If m_canExecuteCache <> temp Then
                m_canExecuteCache = temp
                RaiseEvent CanExecuteChanged(Me, New EventArgs())
            End If
            Return m_canExecuteCache
        End Function
    
        Public Sub Execute(ByVal parameter As Object) Implements ICommand.Execute
            m_executeAction(parameter)
        End Sub
    End Class



    Your viewmodel then exposes a property for the ICommand implementation, which calls private methods on the viewmodel to perform the action when the button is clicked:

    Public Class ColorVM : Implements INotifyPropertyChanged
     
        Private _MainWindowStatusIndicator As String
        Private _ChooseColorCommand As ICommand
     
        Public Sub New()
            Me._ChooseColorCommand = New DelegateCommand(AddressOf ChooseColor, AddressOf CanChooseColor)
        End Sub
        
        Public ReadOnly Property ChooseColorCommand As ICommand
            Get
                Return _ChooseColorCommand
            End Get
        End Property
     
        Public Property MainWindowStatusIndicator As String
            Get
                Return _MainWindowStatusIndicator 
            End Get
            Set(ByVal Value As String)
                _MainWindowStatusIndicator = Value 
                NotifyPropertyChanged("MainWindowStatusIndicator")
            End Set
        End Property
        
        Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
     
        Private Sub NotifyPropertyChanged(ByVal propertyName As String)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
        End Sub
        
        Private Sub ChooseColor(param As Object)
            MainWindowStatusIndicator = "..."
        End Sub
        
        Private Function CanChooseColor(param As Object) As Boolean
            Return True
        End Function
    End Class



    Your XAML then binds to the ICommand implementation, and doesn't use the Click event at all:

    <UserControl x:Class="SampleUserControl"
    
        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" 
    
        mc:Ignorable="d" 
    
        d:DesignHeight="300" d:DesignWidth="300"
    
    >
        <Grid>
            <Button x:Name="Button1" Command="{Binding Path=ChooseColorCommand}"/>
        </Grid>
    </UserControl>


这篇关于TextBlock不使用ViewModel进行更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆