如何使用MVVM同时绑定Progressbar和Datagrid?

时间:2015-01-21 15:10:26

标签: wpf mvvm progress-bar

我正在尝试使用MVVM构建进度条。基本上,我有一个主要的xaml和2个UserControls,1个用于datagrid的进度条1。  我有点新鲜,我跟着this提问和回答,但我没有取得任何成功。下面是我的ViewModel代码和Xaml代码。基本上我有2个问题,

1 - 如何绑定CustomerModels或甚至可能的CustomerViewModel?我试图使用与ObservableCollection直接绑定的Itemsource,我正在填充我的delegateCommand,它与后台工作者一起运行但没有成功。我试过没有代表和后台工作者,只需使用如下。

Me.myLoadCommand = New Commands.LoadCustomerModels()

我做错了什么?

<UserControl.Resources>    
        <vm:CustomerModelsVM x:Key="Customerobj"></vm:CustomerModelsVM>
    </UserControl.Resources>
<Grid >
 <DataGrid x:Name="grdData"  ItemsSource="{Binding Path=CustomerModels}"/>
</Grid>

2 - 如何绑定CurrentProgressBar?我试图以相同的方式绑定进度条状态,但我相信我的ViewModel和Xaml某种程度上没有连接。

<UserControl x:Class="ucProgressBar"
         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" 
                    >
<Grid>
    <ProgressBar Value="{Binding CurrentProgress, Mode=OneWay}"  Visibility="{Binding ProgressVisibility}"></ProgressBar>
    <TextBlock Text="{Binding ElementName=myProgressBar, Path=Value, StringFormat={}{0:0}%}" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>

命名空间ViewModels

Public Class CustomerModelsVM
    Implements ICustomerModelsVM
    Implements INotifyPropertyChanged

    Public Event PropertyChanged As PropertyChangedEventHandler _
     Implements INotifyPropertyChanged.PropertyChanged

    Private ReadOnly worker As BackgroundWorker
    Private m_currentProgress As Integer
    Private _CustomerModels As New ObservableCollection(Of Models.CustomerModel)
    Private mySaveCommand As ICommand
    Private myLoadCommand As ICommand

    Public Sub New()
        Me.worker = New BackgroundWorker()
        Me.myLoadCommand = New DelegateCommand(Sub() Me.worker.RunWorkerAsync(), AddressOf Progressisbusy)
       ' _CustomerModels = getCustomerModels()
        Me.worker = New BackgroundWorker()
        AddHandler Me.worker.DoWork, AddressOf Me.DoWork
        AddHandler Me.worker.ProgressChanged, AddressOf Me.ProgressChanged

    End Sub

    Private Sub ProgressChanged(sender As Object, e As ProgressChangedEventArgs)
        Me.CurrentProgress = e.ProgressPercentage
    End Sub

    Private Function Progressisbusy() As Boolean
        Return Not Me.worker.IsBusy
    End Function

    Private Sub OnPropertyChanged(Optional ByVal propertyName As String = Nothing)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    End Sub

    Public ReadOnly Property CustomerModels() As ObservableCollection(Of Models.CustomerModel)
        Get
            Return _CustomerModels
        End Get
    End Property

    Public ReadOnly Property btnClick() As ICommand
        Get
            Return myLoadCommand
        End Get
    End Property

    Public Property CurrentProgress() As Integer
        Get
            Return Me.m_currentProgress
        End Get
        Private Set(value As Integer)
            If Me.m_currentProgress <> value Then
                Me.m_currentProgress = value
                OnPropertyChanged(Me.CurrentProgress)
            End If
        End Set
    End Property

    Private Sub DoWork(sender As Object, e As DoWorkEventArgs)
            _CustomerModels = getCustomerModels()
    End Sub


    Function getCustomerModels() As ObservableCollection(Of Models.CustomerModel) Implements ICustomerModelsVM.GetCustomerModels

        If _CustomerModels Is Nothing OrElse _CustomerModels.Count = 0 Then myLoadCommand.Execute(_CustomerModels)

        Return _CustomerModels
    End Function

2 个答案:

答案 0 :(得分:1)

您可以将viewmodel添加为包含两个用户控件的主窗口的DataContext。请参考以下代码。

<UserControl x:Class="UserControl1"
             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>
        <DataGrid x:Name="grdData" Height="200"  ItemsSource="{Binding Path=CustomerModels}"/>
    </Grid>
</UserControl>

<UserControl x:Class="UserControl2"
             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" >
    <StackPanel>
        <Button Command="{Binding LoadCommand}">Test</Button>
        <ProgressBar Value="{Binding CurrentProgress, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Height="20" Width="200"
                     Visibility="{Binding ProgressVisibility}"></ProgressBar>        
    </StackPanel>
</UserControl>

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:StakOveflw"
    Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel>
            <local:UserControl1/>
            <local:UserControl2/>
        </StackPanel>
    </Grid>
</Window>

Class MainWindow 
    Public Sub New()
        InitializeComponent()
        Me.DataContext = New CustomerModelsVM()
    End Sub
End Class

Imports System.ComponentModel
Imports System.Collections.ObjectModel
Imports Microsoft.Practices.Prism.Commands
Imports System.Threading

Public Class CustomerModelsVM
    Implements INotifyPropertyChanged

    Public Event PropertyChanged As PropertyChangedEventHandler _
     Implements INotifyPropertyChanged.PropertyChanged

    Private ReadOnly worker As BackgroundWorker
    Private m_currentProgress As Integer

    Private mySaveCommand As ICommand


    Private myLoadCommand As ICommand
    Public Property LoadCommand() As ICommand
        Get
            Return myLoadCommand
        End Get
        Set(ByVal value As ICommand)
            myLoadCommand = value
        End Set
    End Property


    Public Sub New()
        Me.worker = New BackgroundWorker()

        _CustomerModels = New ObservableCollection(Of CustomerModel)()
        AddHandler Me.worker.DoWork, AddressOf Me.DoWork
        AddHandler Me.worker.ProgressChanged, AddressOf Me.ProgressChanged
        Me.worker.WorkerReportsProgress = True
        myLoadCommand = New DelegateCommand(AddressOf LoadClick)

        ' _CustomerModels = getCustomerModels()
    End Sub
    Private Sub LoadClick()
        Me.worker.RunWorkerAsync()
    End Sub
    Private Sub ProgressChanged(sender As Object, e As ProgressChangedEventArgs)
        CurrentProgress = e.ProgressPercentage

    End Sub

    Private Function Progressisbusy() As Boolean
        Return Not Me.worker.IsBusy
    End Function
    Private Function CalculateProgress(total As Integer, complete As Integer) As Integer
        ' avoid divide by zero error
        If total = 0 Then
            Return 0
        End If
        ' calculate percentage complete
        Dim result = CDbl(complete) / CDbl(total)
        Dim percentage = result * 100.0
        ' make sure result is within bounds and return as integer;
        Return Math.Max(0, Math.Min(100, CInt(Math.Truncate(percentage))))
    End Function

    Private Sub OnPropertyChanged(Optional ByVal propertyName As String = Nothing)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    End Sub

    Private _CustomerModels As ObservableCollection(Of CustomerModel)
    Public Property CustomerModels() As ObservableCollection(Of CustomerModel)
        Get
            Return _CustomerModels
        End Get
        Set(ByVal value As ObservableCollection(Of CustomerModel))
            _CustomerModels = value
        End Set
    End Property

    Public Sub GetCustomers()
        Dim total As Integer
        total = 10000
        For index = 1 To total
            Dim a As CustomerModel = New CustomerModel()
            a.NewProperty = "test" + index.ToString()

            Application.Current.Dispatcher.Invoke(Windows.Threading.DispatcherPriority.Background, Function()
                                                                                                       _CustomerModels.Add(a)
                                                                                                   End Function)
            worker.ReportProgress(CalculateProgress(total, index))
        Next
    End Sub

    Public ReadOnly Property btnClick() As ICommand
        Get
            Return myLoadCommand
        End Get
    End Property

    Public Property CurrentProgress() As Integer
        Get
            Return Me.m_currentProgress
        End Get
        Private Set(value As Integer)

            Me.m_currentProgress = value
            OnPropertyChanged("CurrentProgress")

        End Set
    End Property

    Private Sub DoWork(sender As Object, e As DoWorkEventArgs)
        _CustomerModels = getCustomerModels()
    End Sub


    Function getCustomerModels() As ObservableCollection(Of CustomerModel)
        GetCustomers()

        'Application.Current.Dispatcher.BeginInvoke(Windows.Threading.DispatcherPriority.Normal, New Action(Of Integer)(AddressOf GetCustomers), 3)
        Return _CustomerModels
    End Function
End Class

Public Class CustomerModel
    Private newPropertyValue As String
    Public Property NewProperty() As String
        Get
            Return newPropertyValue
        End Get
        Set(ByVal value As String)
            newPropertyValue = value
        End Set
    End Property

End Class

答案 1 :(得分:0)

我想用一个有效的解决方案回答我的问题。在我的情况下问题很简单,我不得不使用调度员来清除我的可观察的收藏品。所以我的Do_work函数如下所示。在开始绑定之前,我没有清除可观察的集合。添加这个简单的行使我的代码工作。

    Private Sub DoWork(sender As Object, e As DoWorkEventArgs)
        Application.Current.Dispatcher.BeginInvoke(Sub() Me.CustomerModels.Clear())

        ' Me.CustomerModels.Clear()
        For index = 1 To 100

            Dim CustomerModel As New CustomerModel With { _
                .age = 30 + index, _
                .name = "testName" & index, _
                .surname = "testSurname" & index, _
                .Id = index}

            Application.Current.Dispatcher.BeginInvoke(Sub() CustomerModels.Add(CustomerModel))
            '  CustomerModels.Add(CustomerModel)
            Thread.Sleep(100)
            worker.ReportProgress(CalculateProgress(100, index))
        Next


    End Sub