我对C#/ WPF的MVVM设计有疑问.我看过几个演示应用程序,但它们并没有真正解决我的问题.我的应用程序由包含其他对象的对象组成.就像父子关系一样.
我现在的问题是:
我有以下情况:
class Child {
string Name;
}
class ChildVM {
Child _child;
string Name{return _child.Name;}
}
class Parent {
string Name;
List<Child> children;
}
class ParentVM{
Parent _parent;
string Name{return _parent.Name;}
List<ChildVM> children {get;set;}
ParentVM(Parent p){_parent = p;}
}
void CreateANewParent(){
List<ChildVM> children = new List<ChildVM>(){new ChildVM(new Child()),...};
ParentVM parent = new ParentVM(new Parent());
foreach(ChildVM child in children)
parent.children.Add(child);
}
Run Code Online (Sandbox Code Playgroud)
这里的问题是,ParentVM包含ChildVM,但实际的Parent(在ParentVM内)没有ChildVM对象包含的Child对象.我也认为复制Child对象不是一个好主意,因为它会导致冗余,在我的应用程序上下文中也没有必要/可能创建新的Child对象.
我还考虑过以下课程设计:
class ParentVM {
Parent _parent;
string Name{return _parent.Name;}
List<Child> children …Run Code Online (Sandbox Code Playgroud) 我最近参数化了我的ViewModel的构造函数.在此之前,我在窗口中这样做:
<Window.DataContext>
<vm:MyViewModel />
</Window.DataContext>
Run Code Online (Sandbox Code Playgroud)
该框架为我实例化了ViewModel.
我知道我可以在代码中设置DataContext,但我更喜欢XAML方式,因此设计人员可以在设计时显示我的测试数据.
这可能吗?
假设您想开发控制器以便使用ViewModel来包含您呈现的视图的数据,那么是否所有数据都包含在ViewModel中?什么条件可以绕过ViewModel?
我问的原因是我处在一些代码使用ViewData而一些代码正在使用ViewModel的位置.我想在团队中分发一套关于何时正确使用ViewData的指南,以及何时只是采用快捷方式.我希望得到其他开发人员的意见,以便我知道我的指导方针不仅仅是我的偏见.
我想在做一些异步操作后将焦点设置在一个SearchBox控件中,我想从我的ViewModel中做到这一点.
我怎么能这样做?
编辑
ViewModel代码:
private bool _searchBarFocused;
public bool SearchBarFocused
{
get { return _searchBarFocused; }
set
{
_searchBarFocused = value;
base.OnPropertyChanged("SearchBarFocused");
}
}
public async Task InitializeData()
{
// Other operations...
SearchBarFocused = true;
}
Run Code Online (Sandbox Code Playgroud)
查看代码隐藏代码:
protected override void OnAppearing()
{
base.OnAppearing();
(this.BindingContext as MyViewModel).InitializeData();
}
Run Code Online (Sandbox Code Playgroud)
SearchBar XAML代码:
<SearchBar SearchCommand="{Binding SearchItemsCommand}">
<SearchBar.Triggers>
<DataTrigger TargetType="SearchBar"
Binding="{Binding SearchBarFocused, Mode=TwoWay}" Value="True">
<Trigger.EnterActions>
<triggers:SearchBarFocusTriggerAction Focused="True" />
</Trigger.EnterActions>
<Trigger.ExitActions>
<triggers:SearchBarFocusTriggerAction Focused="False" />
</Trigger.ExitActions>
</DataTrigger>
</SearchBar.Triggers>
</SearchBar> …Run Code Online (Sandbox Code Playgroud) 我正在研究谷歌的架构组件,以便将ViewModel和LiveData实现到我的应用程序,官方文档说:
注意:由于ViewModel比特定活动和片段实例更长,因此它永远不应引用View或任何可能包含对活动上下文的引用的类.如果ViewModel需要Application上下文(例如,查找系统服务),它可以扩展AndroidViewModel类并具有在构造函数中接收Application的构造函数(因为Application类扩展了Context)
在那之后,我最终得到了这样的代码:
public class ViewModelTest extends AndroidViewModel {
public ViewModelTest(Application application) {
super(application);
}
public void test(){
Prefs.getCurrentCode(getApplication());
}
Run Code Online (Sandbox Code Playgroud)
我应该在活动中正常实例吗?
val viewModel2 = ViewModelProviders.of(this).get(ViewModelTest::class.java)
viewModel2.test()
Run Code Online (Sandbox Code Playgroud)
不是很糟糕吗?要在需要访问SharedPreferences或需要上下文的任何内容时使用此应用程序变量?如果是,我应该避免在ViewModel上使用它并仅在视图上使用它吗?特别是如果我想用一个需要上下文的值更新UI组件.我有点不知道如何解决这个问题,我愿意接受任何建议.
提前致谢
android viewmodel android-context android-application-class android-livedata
我正在我的项目中使用android AAC库和Android数据绑定库.我有AuthActivity和AuthViewModel扩展了android的ViewModel类.在某些情况下,我需要让Activity为ViewModel调用一些方法.例如,当用户点击Google Auth或Facebook Auth按钮时,它在Activity类中初始化(因为初始化GoogleApiClient我需要Activity上下文,我无法传递给ViewModel,视图模型无法存储Activity字段).在Activity类中实现了Google Api和Facebook API的所有逻辑:
//google api initialization
googleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this, this)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
//facebook login button
loginButton.setReadPermissions(Arrays.asList("email", "public_profile"));
loginButton.registerCallback(callbackManager,
Run Code Online (Sandbox Code Playgroud)
此外,我需要调用登录意图,这也需要活动上下文:
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(googleApiClient);
startActivityForResult(signInIntent, GOOGLE_AUTH);
Run Code Online (Sandbox Code Playgroud)
我不能请求facebook登录和google登录,或者从视图模型类请求startActivity intent,所以我创建了类接口AuthActivityListener:
public interface AuthActivityListener {
void requestSignedIn();
void requestGoogleAuth();
void requestFacebookAuth();
void requestShowDialogFragment(int type);
}
Run Code Online (Sandbox Code Playgroud)
在活动类中实现监听器:
AuthActivityRequester authRequestListener = new AuthActivityRequester() {
@Override
public void requestSignedIn() {
Intent intent = new Intent(AuthActivity.this, ScanActivity.class);
startActivity(intent);
AuthActivity.this.finish();
}
@Override
public void requestGoogleAuth() {
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(googleApiClient);
startActivityForResult(signInIntent, GOOGLE_AUTH);
} …Run Code Online (Sandbox Code Playgroud) 我启用了数据绑定,但是在执行代码时出现此错误。
e:[kapt]发生异常:android.databinding.tool.util.LoggedErrorException:发现数据绑定错误。
我创建了一个片段类和该类的XML。我能够导入datbindingutil类。
我已经完成了重建/与gradle文件同步/使缓存无效并重新启动,没有任何效果。
<layout>
<!--suppress AndroidUnknownAttribute -->
<data class=".databinding.ProfileFragmentBinding">
<variable
name="user"
type="com.sample.sample.user.User" />
<variable
name="vm"
type="com.sample.sample.user.UserViewModel" />
<variable
name="handler"
type="com.sample.sample.user.profile.ProfileFragment" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/profileIV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/medium"
android:layout_marginTop="@dimen/medium"
android:contentDescription="@null"
android:src="@mipmap/ic_launcher_round"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:url="@{user.avatarUrl}" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="@+id/profileIV"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@+id/profileIV">
<TextView
android:id="@+id/profileNameLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/myriad_pro_semibold"
android:text="@{user.name}"
android:textColor="@color/black_transparent_de"
android:textSize="@dimen/text_regular"
tools:text="NAME" />
<TextView
android:id="@+id/badgeLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:fontFamily="@font/myriad_pro_semibold"
android:text="@{user.badge}"
android:textColor="@color/grey_000000"
android:textSize="@dimen/text_regular"
tools:text="Superman" />
<TextView
android:id="@+id/profile_Label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:fontFamily="@font/roboto_bold"
android:text="@{user.badge}" …Run Code Online (Sandbox Code Playgroud) 我正在实现一个显示项目列表的wpf应用程序,并提供通过键入文本框来过滤此列表的功能(我认为这是非常简单的用例).
我们正在使用MVVM结构.
我的问题是,谁负责过滤清单?视图还是视图模型?我应该在xaml.cs中实现"OnTextChanged"事件,还是应该在ViewModel中使用属性并使用PropertyChanged来过滤列表.
后续问题是,我应该在ViewModel中使用BindingList/ObservableCollection,还是使用ICollectionView将ItemsControl绑定到?
我尝试了两种方法,但它们都有效.赋予ViewModel责任使得View从代码中保持空白,但另一方面,我并不完全相信应用过滤是ViewModels的责任(例如:不同的视图可能需要不同的过滤)
有什么想法吗?
谢谢,罗尔
编辑:
把它放在ViewModel中让我困扰的是(在我当前的实现中)有一个System.Windows.Data的引用.这是我在ViewModel中没有的参考,因为它显然与View相关.或者我错过了什么?相关代码:
ICollectionView customerView = CollectionViewSource.GetDefaultView(customers);
Run Code Online (Sandbox Code Playgroud) 我正在使用 Android Jetpack (2.2.0-alpha01) 的导航组件。
我希望使用嵌套在我的主 NavHostFragment 中的子 NavHostFragment,它配备了自己的子导航图。请查看以下图片了解上下文:
子导航主机在位于 MainNavHost 堆栈前端的片段中定义如下:
<fragment
android:id="@+id/childNavHostFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="false"
app:navGraph="@navigation/child_graph" />
Run Code Online (Sandbox Code Playgroud)
在 CHILD Nav Host Fragment 前面的片段中,我尝试使用以下代码将 ViewModel 范围限定为 R.navigation.child_graph:
private val childGraphScopedViewModel: ChildGraphScopedViewModel by navGraphViewModels(R.navigation.child_graph) {
viewModelFactory
}
Run Code Online (Sandbox Code Playgroud)
访问 childGraphScopedViewModel 时,我收到错误消息崩溃:
java.lang.IllegalArgumentException: No NavGraph with ID 2131689472 is on the NavController's back stack.
Run Code Online (Sandbox Code Playgroud)
我相信懒惰的 init 调用by navGraphViewModel()是在 mainGraph 中寻找导航图。
如何访问子 navHostFragment 范围的 ViewModel?感谢您的时间。
android viewmodel kotlin android-architecture-navigation android-navigation-graph
我们可以ViewModel使用初始化类
private val viewModel: CharactersViewModel by viewModels()
Run Code Online (Sandbox Code Playgroud)
或者
viewModel = ViewModelProvider(this).get(CharactersViewModel::class.java)
Run Code Online (Sandbox Code Playgroud)
这里的 CharactersViewModel 是我们的 ViewModel 类。我的问题是什么时候使用哪个?两者都包含相同的目的吗?我已经阅读了 ViewModel 的 android 官方文档。文档说by viewModels()Kotlin 属性委托。但可惜没能看懂。任何人都可以帮助我理解这一点吗?
viewmodel ×10
android ×5
mvvm ×5
kotlin ×3
wpf ×3
.net ×1
android-architecture-navigation ×1
asp.net-mvc ×1
c# ×1
collections ×1
data-binding ×1
focus ×1
listener ×1
viewdata ×1
xaml ×1