我有2个任务。
我在完成与数据绑定和命令绑定相关的任务2时遇到问题。
如果有人知道如何执行任务2,请添加一些代码。 这是我对这两个任务的实现,以防有人想要解决它..:
我有一个名为" Book"的用户控件。包含3个文本块和一个按钮。 userControl具有我的图书模型的dependecyProperty和按钮命令。
Book.xaml
<UserControl x:Name="MyBookControl"
<Grid DataContext="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Controls:BookControl}}, Path=TheBook}">
<Label Grid.Row="0">Title</Label>
<Label Grid.Row="1">Author</Label>
<Label Grid.Row="2">Description</Label>
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Title}"/>
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Author}"/>
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Description}"/>
<Button Grid.Row="3" Command="{Binding
SomeCommand,ElementName=MyBookControl}" Content="Save" />
</Grid>
Book.xaml.cs
public partial class BookControl : UserControl
{
public BookControl()
{
InitializeComponent();
}
public BookModel TheBook
{
get { return (BookModel)GetValue(TheBookProperty); }
set { SetValue(TheBookProperty, value); }
}
public static DependencyProperty TheBookProperty = DependencyProperty.Register("TheBook", typeof(BookModel), typeof(BookControl));
public ICommand SomeCommand
{
get { return (ICommand)GetValue(SomeCommandProperty); }
set { SetValue(SomeCommandProperty, value); }
}
public static readonly DependencyProperty SomeCommandProperty =
DependencyProperty.Register("SomeCommand", typeof(ICommand), typeof(BookControl), new UIPropertyMetadata(null));
}
BookModel.cs
public class BookModel
{
public string Title { get; set; }
public string Author { get; set; }
public string Description { get; set; }
}
为了完成任务1,我创建了一个窗口: BookWindow
<Window
DataContext="{Binding Source={StaticResource Locator}, Path=Main}"
>
<StackPanel>
<Controls:BookControl TheBook="{Binding Book}" SomeCommand="{Binding
SaveCommand}" />
</StackPanel>
BookViewModel.cs
public BookModel Book { get; set; }
public MainViewModel()
{
Book = new BookModel{Title = "A Book", Author = "Some Author",
Description = "Its a really good book!"};
}
private ActionCommand _SaveCommand;
public ICommand SaveCommand
{
get
{
if (_SaveCommand == null)
{
_SaveCommand = new ActionCommand(OnSaveCommand, CanSaveCommand);
}
return _SaveCommand;
}
}
protected virtual void OnSaveCommand()
{
MessageBox.Show("save clicked");
}
protected virtual bool CanSaveCommand()
{
return true;
}
现在,尝试完成任务2:
ContainerWindow:
<Window
DataContext="{Binding Source={StaticResource Locator}, Path=Container}"
>
<StackPanel>
<ItemsControl ItemsSource="{Binding Books}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Controls:BookControl />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
ContainerViewModel.cs:
private ObservableCollection<BookModel> books;
public ObservableCollection<BookModel> Books
{
get
{
if (books == null)
{
// Not yet created.
// Create it.
books = new ObservableCollection<BookModel>();
}
return books;
}
}
public ContainerViewModel()
{
BookModel book1 = new BookModel { Title = "A Book 2", Author = "Some Author", Description = "Its a really good book!" };
BookModel book2 = new BookModel { Title = "A Book 3", Author = "Some Author", Description = "Its a really good book!" };
Books.Add(book1);
Books.Add(book2);
}
绑定失败,按钮&#34;保存&#34;停止重新编码。 https://onedrive.live.com/redir?resid=3A8F69A0FB413FA4!121&authkey=!AKnyQk6Ge_9QHug&v=3&ithint=photo%2cpng
那么,发生了什么?为什么绑定失败,为什么按钮&#34;保存&#34;不起作用?
答案 0 :(得分:1)
您未在列表示例中设置DependencyProperties。
<DataTemplate>
<Controls:BookControl />
</DataTemplate>
看看你是如何在非列表版本中完成的。
<Controls:BookControl TheBook="{Binding Book}" SomeCommand="{Binding
SaveCommand}" />
话虽如此,您根本不需要DependencyProperties,UserControl将继承每个Book&#39;在ItemsControl创建它们的书籍列表中。您只需要不在网格上设置DataContext。
然后你的按钮可以绑定到BookViewModel命令属性。
<Button Grid.Row="3" Command="{Binding SaveCommand}" Content="Save" />
如果您的担忧不知道继承的DataContext可用的内容,您可以这样做以获得设计时支持。
d:DataContext="{d:DesignInstance Type=local:BookViewModel,
IsDesignTimeCreatable=False}"
只需确保在文件中的某处定义了以下内容,通常是默认情况下。
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
<强>更新强>
所以我错过了第二个问题,应该实际上已经启动了Visual Studio。问题是您的命令位于MainViewModel.cs中。也就是说,我们的UserControl继承了每个Book对象的DataContext。缺点是按钮正在Book对象中查找命令。
我将假设您有一个保存命令,您将编辑Book对象。因此,让我们借此机会继续制作一个ViewModel。我要将save命令移动到那里,以便保存总是可以通过BookViewModel获得。可以有充分的理由在其他地方使用save命令,但为了简单起见,我们将它放在ViewModel中。
此外,我不确定您是否在任何地方实施了INotifyPropertyChanged,因为您的MainViewModel和ContainerViewModel没有显示使用了一个。如果您不这样做,我强烈建议您退后一步,查看ViewModel的实现或MVVM框架。
BookViewModel.cs
public class BookViewModel
{
private readonly BookModel book;
public BookViewModel(BookModel book)
{
this.book = book;
SaveCommand = new ActionCommand(OnSaveCommand, CanSaveCommand);
}
public ICommand SaveCommand { get; private set; }
public string Title
{
get { return book.Title; }
set { book.Title = value; }
}
public string Author
{
get { return book.Author; }
set { book.Author = value; }
}
public string Description
{
get { return book.Description; }
set { book.Description = value; }
}
protected virtual void OnSaveCommand()
{
MessageBox.Show("Save clicked for the book '" + Title + "'.");
}
protected virtual bool CanSaveCommand()
{
return true;
}
}
这是你可能想要做的一个非常基本的例子。我想保持简单,不要脱离示例,你可能想要至少做一些空检查。
通过上述内容,您不必更改任何UserControl,我必须添加行和列定义,但我最终得到以下内容:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0">Title</Label>
<TextBlock Grid.Row="0"
Grid.Column="1"
Text="{Binding Title}" />
<Label Grid.Row="1" Grid.Column="0">Author</Label>
<TextBlock Grid.Row="1"
Grid.Column="1"
Text="{Binding Author}" />
<Label Grid.Row="2" Grid.Column="0">Description</Label>
<TextBlock Grid.Row="2"
Grid.Column="1"
Text="{Binding Description}" />
<Button Grid.Row="3"
Grid.Column="0"
Command="{Binding SaveCommand}"
Content="Save" />
</Grid>
希望您注意到我们的BookViewModel构造函数接受了一本书,这意味着我们需要更改ContainerViewModel以容纳正确的集合并正确创建它们。
public class ContainerViewModel
{
private ObservableCollection<BookViewModel> books;
public ContainerViewModel()
{
Books.Add(
new BookViewModel(new BookModel
{
Title = "A Book 2",
Author = "Some Author",
Description = "Its a really good book!"
}));
Books.Add(
new BookViewModel(new BookModel
{
Title = "A Book 3",
Author = "Some Author",
Description = "Its a really good book!"
}));
}
public ObservableCollection<BookViewModel> Books
{
get
{
if (books == null)
{
// Not yet created.
// Create it.
books = new ObservableCollection<BookViewModel>();
}
return books;
}
}
}
所有这些以及您的ItemsControl可以简单地如下:
<ItemsControl ItemsSource="{Binding Path=Books}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:MyBookControl />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>