问题始于这篇文章:Using binding to a List<UserControl> how can I do for not showing the controls
我正在设计这样的东西:
List<Container>
(Below container properties)
- Objective: string
- Problems: List<ProblemUserControl>
ProblemUserControls是一个UserControl,其中包含一个名为Problem的额外属性。但上面的帖子一个人建议我使用MVVM Pattern。我正在调查,但我仍然感到困惑,或者我需要一些帮助来理解WPF中的模式。
答案 0 :(得分:1)
该模式是关于在软件的逻辑层之间保持适当的分离和依赖关系。您在示例中将显示逻辑与业务逻辑混淆,因为您将模型代码(目标容器)与显示代码(用户控件列表)混合在一起。
相反,请保持目标并维持List<Problem>
而不是List<ProblemUserControl>
。然后使用WPF和绑定将ProblemUserControl
与Problem
相关联。您的用户控件了解Problem
是什么,因此您可以绑定Problem
上的属性。通过这种方式,您可以对图层进行隔离,从而更容易推断出您的软件。
答案 1 :(得分:1)
以下是使用MVVM进行说明的示例。请注意,不需要有一个用户控件列表,从MVVM角度来看,这实际上被认为是不正确的。
这是基于Visual Studio中的默认WPF应用程序模板。
以下是所涉及的课程。
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler changed = PropertyChanged;
if (changed != null)
{
changed(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class Container : ViewModelBase
{
private string m_Objective;
private ProblemCollection m_Problems;
public Container()
{
m_Problems = new ProblemCollection();
}
public string Objective
{
get { return m_Objective; }
set
{
m_Objective = value;
OnPropertyChanged("Objective");
}
}
public ProblemCollection Problems
{
get { return m_Problems; }
set
{
m_Problems = value;
OnPropertyChanged("Problems");
}
}
}
public class Problem : ViewModelBase
{
private string m_Name;
public string Name
{
get { return m_Name; }
set
{
m_Name = value;
OnPropertyChanged("Name");
}
}
}
public class ProblemCollection : ObservableCollection<Problem>
{
}
主窗口。请注意,我已注释掉您的矩形以显示绑定
<Window x:Class="StackOverflowDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBlock TextWrapping="Wrap" Text="{Binding Objective}" Grid.Column="0" VerticalAlignment="Center"
FontWeight="Bold" />
<ItemsControl ItemsSource="{Binding Problems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<!--<Rectangle Stroke="Black" Height="20" Width="20" Margin="1,0" />-->
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>
MainWindow.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// Create dummy test data.
// Normally this will be passed to the window or set externally
var container = new Container();
container.Problems.Add(new Problem {Name = "Foo"});
container.Problems.Add(new Problem {Name = "Bar"});
container.Problems.Add(new Problem {Name = "hello"});
container.Problems.Add(new Problem {Name = "world"});
DataContext = container;
}
}