我正在尝试使用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
答案 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