【发布时间】:2019-10-28 10:18:43
【问题描述】:
我正在学习 MVVM 模式,但在数据绑定方面遇到了一些问题。我了解它的工作原理,但在我的示例中,它使用了错误的 DataContext 来搜索绑定。
我没有找到适合我的问题的另一个问题。
所以我有这个观点:
<UserControl x:Class="Kenshinaro.CashRegister.UI.View.CashRegister.CashRegisterChoiceView"
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="450" d:DesignWidth="800">
<ItemsControl ItemsSource="{Binding CashRegisters}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel></WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</UserControl>
使用以下 ViewModel:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Kenshinaro.CashRegister.UI.View.CashRegister;
namespace Kenshinaro.CashRegister.UI.ViewModel.CashRegister
{
public class CashRegisterChoiceViewModel : MVVM.ViewModel
{
private ObservableCollection<CashRegisterItemsControlView> _cashRegisters = new ObservableCollection<CashRegisterItemsControlView>()
{
new CashRegisterItemsControlView()
{
DataContext = new CashRegisterItemsControlViewModel()
{
View = new CashRegisterCardView()
{
DataContext = new CashRegisterCardViewModel()
{
Model = new Model.CashRegister()
{
Name = "1"
}
}
}
}
},
new CashRegisterItemsControlView()
{
DataContext = new CashRegisterItemsControlViewModel()
{
View = new CashRegisterCardView()
{
DataContext = new CashRegisterCardViewModel()
{
Model = new Model.CashRegister()
{
Name = "2"
}
}
}
}
},
new CashRegisterItemsControlView()
{
DataContext = new CashRegisterItemsControlViewModel()
{
View = new CashRegisterCardView()
{
DataContext = new CashRegisterCardViewModel()
{
Model = new Model.CashRegister()
{
Name = "3"
}
}
}
}
}
};
public ObservableCollection<CashRegisterItemsControlView> CashRegisters
{
get => _cashRegisters;
set => SetProperty(ref _cashRegisters, value);
}
}
}
(我的基础 ViewModel 类正在实现 INotifyPropertyChanged 接口)
所以这个视图显示了这个视图的列表:
<UserControl x:Class="Kenshinaro.CashRegister.UI.View.CashRegister.CashRegisterItemsControlView"
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"
xmlns:local="clr-namespace:Kenshinaro.CashRegister.UI.View.CashRegister"
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<md:Card Margin="10">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<local:CashRegisterCardView Padding="5"/>
<Button Margin="20" Grid.Row="1" Content="Pick me"/>
</Grid>
</md:Card>
</UserControl>
视图模型:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Kenshinaro.CashRegister.UI.ViewModel.CashRegister
{
public class CashRegisterItemsControlViewModel : MVVM.ViewModel
{
private View.CashRegister.CashRegisterCardView _view;
public View.CashRegister.CashRegisterCardView View
{
get => _view;
set => SetProperty(ref _view, value);
}
}
}
这个视图也显示了这个视图:
<UserControl x:Class="Kenshinaro.CashRegister.UI.View.CashRegister.CashRegisterCardView"
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"
xmlns:local="clr-namespace:Kenshinaro.CashRegister.UI.View.CashRegister"
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" Background="White" >
<Grid>
<TextBlock Text="{Binding DataContext.Name, RelativeSource={RelativeSource AncestorType=local:CashRegisterCardView}}"/>
</Grid>
</UserControl>
视图模型:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Kenshinaro.CashRegister.Model;
namespace Kenshinaro.CashRegister.UI.ViewModel.CashRegister
{
public class CashRegisterCardViewModel : MVVM.ViewModel
{
private Model.CashRegister _model;
public Model.CashRegister Model
{
get => _model;
set => SetProperty(ref _model, value);
}
public String Name
{
get => _model.Name;
set => _model.Name = value;
}
}
}
现在,如果我启动应用程序,最后一个视图中的 TextBlock 上的绑定不会出现。 VisualStudio 的输出显示:
System.Windows.Data 错误:40:BindingExpression 路径错误:在“对象”“CashRegisterItemsControlViewModel”(HashCode=35528341)上找不到“名称”属性。 BindingExpression:Path=DataContext.Name; DataItem='CashRegisterCardView' (名称='');目标元素是'TextBlock'(名称='');目标属性是“文本”(类型“字符串”)
我可以摆脱它,它正在 CashRegisterItemsControlView 的 DataContext 中搜索属性,但我只是不明白为什么,因为我在集合初始化时手动设置了 DataContext(仅用于测试):
private ObservableCollection<CashRegisterItemsControlView> _cashRegisters = new ObservableCollection<CashRegisterItemsControlView>()
{
new CashRegisterItemsControlView()
{
DataContext = new CashRegisterItemsControlViewModel()
{
View = new CashRegisterCardView()
{
DataContext = new CashRegisterCardViewModel()
{
Model = new Model.CashRegister()
{
Name = "1"
}
}
}
}
},
...
那么为什么它仍然使用错误的 DataContext?
现在,当我将绑定更改为 View.DataContext.Name 时,它正在手动设置的 DataContext 中搜索:
System.Windows.Data 错误:40:BindingExpression 路径错误:在“对象”“CashRegisterCardView”(名称=“”)上找不到“视图”属性。 BindingExpression:Path=View.DataContext.Name; DataItem='CashRegisterCardView' (名称='');目标元素是'TextBlock'(名称='');目标属性是“文本”(类型“字符串”)
我真的很困惑..希望你能帮助我。
谢谢!
如果您需要有关其他课程的信息,请询问。我不想在问题中添加更多代码,因为它已经足够长了。
【问题讨论】:
-
首先,永远不要在视图模型中创建视图元素。这不是 MVVM 的意义所在。通常,为某些视图模型类型声明 DataTemplates。然后视图元素将由这些模板自动生成。从这里开始阅读:Data Templating Overview.
-
@Clemens 正如我提到的集合初始化只是为了测试。绑定问题解决后,将彻底重做。我正在使用 ItemsControl 测试 MVVM。不过谢谢你的建议。
-
作为一般规则,永远不要显式设置任何 DataContext,Window 或 Page 除外。具体来说,对于 ItemsControls,各个项目容器的 DataContext 会(由框架)自动设置为 ItemsSource 集合的适当项目。
标签: c# wpf xaml mvvm data-binding