gpt4 book ai didi

使用 mvvm 模式的 WPF 数据绑定(bind)问题

转载 作者:行者123 更新时间:2023-12-03 10:20:19 24 4
gpt4 key购买 nike

我创建了一个用户控件“SearchControl”(也将在其他屏幕中进一步重复使用。
搜索控件->

<usercontrol name="SearchControl"......>
<stackpanel orientation="horizontal"...>

<TextBox Text"{Binding Path=UserId}"...>

<Button Content="_Search" ....Command="{Binding Path=SearchCommand}"..>

</stackpanel>
</usercontrol>

public partial class SearchControl : UserControl
{
public SearchControl()
{
InitializeComponent();
DataContext=new UserViewModel();
}
}

然后我在窗口“UserSearch”中使用这个控件
<window name="UserSearch".............
xmlns:Views="Namespace.....Views">
<Grid>
<Grid.RowDefinitions>
<RowDefinition..../>
<RowDefinition..../>
<RowDefinition..../>
<RowDefinition..../>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition..../>
<ColumnDefinition..../>
</Grid.ColumnDefinitions>

<Views:SearchControl Grid.Row="0" Grid.Colspan="2"/>
<TextBlock Text="User Id" Grid.Row="1" Grid.Column="0"..../>
<TextBox Text="{Binding Path=UserId}" Grid.Row="1" Grid.Column="1".../>

<TextBlock Text="First Name" Grid.Row="2" Grid.Column="0"..../>
<TextBox Text="{Binding Path=FirstName}" Grid.Row="2" Grid.Column="1".../>

<TextBlock Text="Last Name" Grid.Row="3" Grid.Column="0"..../>
<TextBox Text="{Binding Path=LastName}" Grid.Row="3" Grid.Column="1".../>
</Grid>
</window>

public partial class UserSearch : Window
{
public UserSearch()
{
InitializeComponent();
DataContext=new UserViewModel();
}
}

我的目标是:
当我在 SearchControl 的文本框中输入 UserId 并单击 Search 按钮时,检索到的结果记录应显示在 UserId、FirstName、LastName 的文本框中
class UserViewModel:INotifyPropertyChanged
{
DBEntities _ent; //ADO.Net Entity set

RelayCommand _searchCommand;

public UserViewModel()
{
_ent = new DBEntities();
}

public string UserId {get; set;}
public string FirstName {get; set;}
public string LastName {get; set;}

public ICommand SearchCommand
{
get
{
if(_searchCommand == null)
{
_searchCommand = new RelayCommand(param = > this.Search());
}
return _searchCommand;
}
}

public void Search()
{
User usr = (from u in _ent
where u.UserId = UserId
select u).FirstOrDefault<User>();

UserId = usr.UserId;
FirstName = usr.FirstName;
LastName = usr.LastName;

OnPropertyChanged("UserId");
OnPropertyChanged("FirstName");
OnPropertyChanged("LastName");
}

public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if(PropertyChanged != null)
PropertyChanged(this, new PropertChangedEventArgs(propertyName);
}
}

在这里,由于我为 SearchControl 和 UserSearch 使用 UserViewModel 的两个单独实例,即使我在通过 UserId 搜索时检索特定用户的记录,我也无法将属性 UserId、FullName、LastName 与相应的文本框绑定(bind)。 .如何解决这个问题?

最佳答案

1)不要让 View 初始化表示模型,它应该是相反的。表示模型是感兴趣的对象,而不是特定的 View 。

public interface IView
{
void SetModel(IPresentationModel model);
}

publiv class View : UserControl, IView
{
public void SetModel(IPresentationModel model)
{
DataContext = model;
}
}

public class PresentationModel : IPresentationModel
{
public PresentationModel(IView view)
{
view.SetModel(this);
}
}

2)不要在代码隐藏文件中设置 subview 的数据上下文。通常,使用 subview 的 View 会在 xaml 文件中设置数据上下文。

3)通常每个 View 都有自己的表示模型。表示模型应该有一种 View 。这意味着单个表示模型的不同 View 可能在外观上有所不同,但在功能上可能不同(在您的情况下,一个 View 用于搜索,另一个 View 用于显示和编辑数据)。所以,你已经通过了单一职责原则。

4)抽象您的数据访问层,否则您将无法对您的表示模型进行单元测试(因为它需要直接访问数据库)。定义存储库接口(interface)和实现:
public interface IUserRepository
{
User GetById(int id);
}

public class EntityFrameworkUserRepository : IUserRepository
{
private readonly DBEntities _entities;

public EntityFrameworkUserRepository(DBEntities entities)
{
_entities = entities;
}

public User GetById(int id)
{
return _entities.SingleOrDefault(u => u.UserId == id);
}
}

5)不要使用FirstOrDefault,因为一个ID是唯一的,所以一个ID不能有多个用户。如果找到多个结果,SingleOrDefault(在上面的代码片段中使用)会引发异常,但如果没有找到则返回 null。

6)直接绑定(bind)到您的实体:
public interface IPresentationModel
{
User User { get; }
}

<StackPanel DataContext="{Binding Path=User}">
<TextBox Text="{Binding Path=FirstName}" />
<TextBox Text="{Binding Path=LastName}" />
</StackPanel>

7) 使用 CommandParameter 直接通过命令提供您正在搜索的用户 ID。
<TextBox x:Name="UserIdTextBox">

<Button Content="Search" Command="{Binding Path=SearchCommand}"
CommandParameter="{Binding ElementName=UserIdTextBox, Path=Text}" />

public class PresentationModel
{
public ICommand SearchCommand
{
// DelegateCommand<> is implemented in some of Microsoft.BestPractices
// assemblies, but you can easily implement it yourself.
get { return new DelegateCommand<int>(Search); }
}

private void Search(int userId)
{
_userRepository.GetById(userId);
}
}

8) 如果只是数据绑定(bind)导致问题,请查看以下网站以了解如何调试 wpf 数据绑定(bind): http://beacosta.com/blog/?p=52

9) 不要使用包含属性名称的字符串。一旦你重构了你的代码并且属性改变了它们的名字,你将很难在字符串中找到所有的属性名并修复它们。改用 lambda 表达式:
public class PresentationModel : INotifiyPropertyChanged
{
private string _value;
public string Value
{
get { return _value; }
set
{
if (value == _value) return;

_value = value;
RaisePropertyChanged(x => x.Value);
}
}

public PropertyChangedEventHandler PropertyChanged;

public void RaisePropertyChanged(Expression<Func<PresentationModel, object>> expression)
{
if (PropertyChanged == null) return;

var memberName = ((MemberExpression)expression.Body).Member.Name;
PropertyChanged(this, new PropertyChangedEventArgs(memberName));
}
}

我希望你能最好地解决你的问题,我希望我能帮助你一点。

最好的祝福
奥利弗·哈纳皮

关于使用 mvvm 模式的 WPF 数据绑定(bind)问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1548376/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com