我为这个冗长的问题道歉,但我希望你能坚持下去。我试图尽力包含所有相关的代码片段,以便准确解释我想要实现的目标。
我正在尝试将我的移动应用程序转换为MVVM设计模式,我在使用模型中发生的更改更新View时遇到了一些困难。
我已将我的应用程序拆分为经典的模型,视图,视图模型结构。
目前,我正在尝试将数据从我的模型SoundScapeData.cs
传播到我的视图HomePage.xaml
。
我的HomePage.xaml
代码隐藏文件如下所示:
namespace AX2018
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class HomePage : ContentPage
{
public HomePage()
{
InitializeComponent();
BindingContext = new HomePageViewModel();
}
private void OnConnectButtonClicked(object sender, EventArgs e)
{
Bluetooth bluetooth = new Bluetooth();
bluetooth.Connect();
}
}
}
如您所见,我使用BindingContext
关键字绑定数据并将其绑定到HomePageViewModel
类的新实例。
我正在连接蓝牙设备,因此拨打bluetooth.Connect()
的电话会在点击Button
视图中的HomePage.xaml
时调用。然后,此蓝牙设备使用特定值更新应用程序。
我想强调的是,蓝牙连接运行良好,并且已经过验证,可以使用View previous 转换为MVVM设计模式。
我的ViewModel HomePageViewModel.cs
,如下所示:
namespace AX2018
{
public class HomePageViewModel
{
private SoundScapeData _soundScapeData;
public SoundScapeData SoundScapedata { get { return _soundScapeData; } }
public HomePageViewModel()
{
_soundScapeData = new SoundScapeData();
}
}
}
另一方面,我对如何设计视图模型感到有些困惑,因为模型SoundScapeData.cs
目前非常简单。这个中间视图模型甚至是必要的吗?
这是我的SoundScapeData.cs
模型:
namespace AX2018
{
public class SoundScapeData : INotifyPropertyChanged
{
private double _spl;
public double SPL
{
get { return _spl; }
set
{
_spl = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
从模型中可以看出,它实现了INotifyPropertyChanged
接口,并具有相关函数来处理方法OnPropertyChanged()
中的事件。
我的观点HomePage.xaml
相当冗长 - 它由一个9 x 3网格组成,标签放置在某些位置。这些标签应该反映SoundScapeData.cs
模型中的值(以及其他模型,但这是在路上)。以下是相关摘要:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:AX2018"
x:Class="AX2018.HomePage">
<ContentPage.BindingContext>
<local:HomePageViewModel/>
</ContentPage.BindingContext>
...
<Label Text="{Binding SoundScapedata.SPL}"
FontSize="68" Style="{StaticResource ColoredLabel}"
Grid.Row="4"
Grid.Column="1"
Margin="-20"></Label>
正如您所看到的,我已将视图HomePage.xaml
中的数据绑定到视图模型HomePageViewModel.cs
,该模型包含SoundScapeData.cs
模型的实例,后者又实现{ {1}}界面。
据我所知,在使用MVVM设计模式时,这是数据绑定方面的正确方法。但是,SPL中的更改未反映在我的视图INotifyPropertyChanged
中。
我在单独的类HomePage.xaml
中更新SPL值,该类继承自Bluetooth.cs
模型。以下是来自SoundScapeData.cs
类的Connect()
方法的摘录:
Bluetooth
再次,我为这个相当长的问题道歉,但我希望有人可以向我指出我做错了什么。我想重申一下,SPL值在View previous 中更新为转换为MVVM,所以我肯定在做数据绑定时出错了。
提前谢谢你,
kdhansen
答案 0 :(得分:1)
我会在这里回答,因为评论太短暂无法解释。如果我误解了一些名字,请原谅我:P 让我们总结一下你的情景:
现在:
主页(查看)
我真的不知道在Xamarin oyu中是否必须复制此内容,请记住在后面的代码中设置它。
<ContentPage.BindingContext>
<local:HomePageViewModel/>
</ContentPage.BindingContext>
你也应该改变这个:
<Label Text="{Binding Spl}" <!--You dont need SoundScapeData anymore this is the public VM property -->
FontSize="68" Style="{StaticResource ColoredLabel}"
Grid.Row="4"
Grid.Column="1"
Margin="-20"></Label>
<强> HomePageViewModel 强>
它应该具有您需要的任意数量的属性。假设您的模型只有一个属性 SPL 。那就是你的模型现在你必须通过你的VM把它放到View中。因此,您的VM应该具有一个属性(公共/私有),以使其适应View和您的模型。
private string spl;
public string Spl
{
get {return this.spl;}
set
{
if (this.spl != value)
{
this.spl = value;
OnPropertyChanged("SPL);
}
单击按钮并连接到蓝牙或其所做的任何事情(; P),因为它更改了模型,您必须更改VM属性。请记住,您的模型必须与VM中的实例相同。
所以...你应该附加到Model属性更改,以便更改VM属性,最好的方法是创建一个类(让我们尝试尽可能多地应用SOLID)
public class YourNewDataSource
{
#region Attributes
private readonly HomePageViewModel homePageViewModel;
#endregion
#region Public Methods
public YourNewDataSource(HomePageViewModel homePageViewModel)
{
this.homePageViewModel = homePageViewModel;
}
public void Initialize()
{
this.homePageViewModel.SoundScapeData.PropertyChanged += this.OnHomePageModelPropertyChanged;
}
#endregion
#region Event Handlers
private void OnHomePageModelPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "SPL":
this.homePageViewModel.Spl = this.homePageViewModel.SoundScapeData.Spl;
break;
}
}
#endregion
}
现在,当您启动应用程序或想要显示视图时,您必须使用VM创建新的YourNewDataSource:
public HomePage()
{
InitializeComponent();
HomePageViewModel homePageViewModel = new HomePageViewModel();
YourNewDataSource yourNewDataSource = new YourNewDataSource(homePageViewModel)
BindingContext = homePageViewModel;
}
看看,尝试一下,然后问你是不是得到了一些我在这里写的:D
我刚刚看了你的bluetooth.Connect。
我不知道蓝牙类是否必须从SoundScapeData继承,但是现在它不起作用会导致您在连接时丢失VM的模型。如果您不需要继承SoundScapeData,只需在connect方法中添加一个参数,并将Vm.SoundScapeData传递给它。
答案 1 :(得分:0)
您的问题是您正在更改模型的实例并失去视图的绑定。 Juan Carlos的回答是正确的,你不是应用纯MVVM,视图不应该知道模型,viewmodel负责使模型适应视图。 您在视图后面的代码中的OnConnectButtonClicked也不应用MVVM模式,您应该使用命令。链接http://www.learnmvvm.com/是一个很好的起点。
如果您将代码的示例项目上传到某个存储库,我将通过应用MVVM和SOLID原则对其进行修改。