Raise usercontrol commands from a parent window using mvvm pattern - wpf

My WCF application supports downloading books from a remote service. The user sends a request to the service to download a book, the service gets the request and downloads the book. in response, it sends the download progress for the requested book.
Each element in the BookContainer is a userControl of Book.xaml and its logic represented by bookviewmodel.cs class.
When the user clicks on each book element in the BookContainer.xaml window, the click command inside the bookviewmodel is raised as expected.
I need the help to implement "DownlaodAllCommand" inside containerviewmodel to raise each DownloadCommand of each book.
How should it be implemented using the mvvm pattern.
BookContainer view :
https://onedrive.live.com/redir?resid=3A8F69A0FB413FA4!124&authkey=!ANdfYAk6f0Vf-8s&v=3&ithint=photo%2cpng
code behind:
BookContainer.xaml:
<Window x:Name="BookContainer"
DataContext="{Binding Source={StaticResource Locator}, Path=ContainerViewModel}">
<DockPanel>
<ItemsControl DockPanel.Dock="Top" ItemsSource="{Binding Books}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate >
<Controls:BookControl />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button DockPanel.Dock="Bottom" Command="{Binding DownloadAllCommand}" Content="Download All" > </Button>
</DockPanel>
</Window>
ContainerViewModel
public class ContainerViewModel : ViewModelBase
{
private ObservableCollection<BookViewModel> books;
public ObservableCollection<BookViewModel> Books
{
get
{
if (books == null)
{
// Not yet created.
// Create it.
books = new ObservableCollection<BookViewModel>();
}
return books;
}
}
private ActionCommand _DownloadAllCommand;
public ICommand DownloadAllCommand
{
get
{
if (_DownloadAllCommand == null)
{
_DownloadAllCommand = new ActionCommand(OnDownloadAllCommand, CanDownloadAllCommand);
}
return _DownloadAllCommand;
}
}
private void OnDownloadAllCommand()
{
// help !
}
private bool CanDownloadAllCommand()
{
return true;
}
}
Book.xaml
<UserControl
<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.Column="2" Grid.RowSpan="3" Command="{Binding DownloadCommand}" Content="Download" />
<Ellipse Grid.Column="3"
Height="20" Width="20"
Stroke="Black"
StrokeThickness="0.5"
HorizontalAlignment="Center"
Grid.Row="1"
/>
<Controls:PieSlice Grid.Column="3" Grid.Row="1" Stroke="Black" Fill="Black"
Height="20" Width="20"
StartAngle="0" EndAngle="{Binding Percent}"
HorizontalAlignment="Center" />
</UserControl>
BookViewModel
public class BookViewModel : ViewModelBase
{
public delegate void DownloadRequest(string name);
public event DownloadRequest OnDownalodRequest;
public BookViewModel(BookModel model)
{
this.Book = model;
}
private ActionCommand _DownloadCommand;
public ICommand DownloadCommand
{
get
{
if (_DownloadCommand == null)
{
_DownloadCommand = new ActionCommand(OnDownloadCommand, CanDownloadCommand);
}
return _DownloadCommand;
}
}
protected virtual void OnDownloadCommand()
{
if (OnDownalodRequest != null)
{
OnDownalodRequest.Invoke(this.Author);
}
}
}
BookModel
public class BookModel
{
public string Title { get; set; }
public string Author { get; set; }
public string Description { get; set; }
public Status Status { get; set; }
}

Insid the ContainerViewModel, method OnSaveAllCommand():
Books.ToList().Foreach(book =>
{
if(book.SaveCommand.CanExecute() == false) return;
book.SaveCommand.Execute()
}
);
but take in account that this is a bad practice to use a viewmodel from another viewmodel, try to perform viewmodels communnication on a model level.

Related

WPF C# Command Binding

I have problem with binding, I want to navigate to new Page (not new window). I Have tried by click event, this is working but if I am trying by ICommand interface, it isn't working good. I don't want why, i have tried in cross-platform, everything works fine. I am thinking what's is wrong with that code.
Main XAML
<Window x:Class="WpfAppFP.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfAppFP"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
Background="#67696d"
x:Name="_CLK">
<Window.Content>
<Border Background="#202021" CornerRadius="40" >
<StackPanel Margin="20">
<Label Content="Type in your data" Foreground="White" HorizontalAlignment="Center" FontSize="20" FontWeight="Bold"/>
<Separator/>
<Label Content="Name" HorizontalAlignment="Center" Foreground="White" FontWeight="Bold"/>
<TextBox HorizontalAlignment="Center" MinWidth="320" MinHeight="32" Foreground="Black" Background="#f5ddff" FontSize="15" FontWeight="DemiBold"/>
<Label Content="Surname" HorizontalAlignment="Center" Foreground="White" FontWeight="Bold"/>
<TextBox HorizontalAlignment="Center" MinWidth="320" MinHeight="32" Foreground="Black" Background="#f5ddff" FontSize="15" FontWeight="DemiBold"/>
<Label Content="Social" HorizontalAlignment="Center" Foreground="White" FontWeight="Bold"/>
<TextBox HorizontalAlignment="Center" MinWidth="320" MinHeight="32" Foreground="Black" Background="#f5ddff" FontSize="15" FontWeight="DemiBold" MaxLength="11" />
<Separator Margin="0,10,0,0"/>
<Button HorizontalAlignment="Center" MinHeight="32" MinWidth="120" Foreground="Black" Background="White" Margin="0,10,0,0" Content="Login" FontWeight="Bold" BorderThickness="2"
x:Name="BtnClk" Command="{Binding CandidatesVM}"/>
</StackPanel>
</Border>
</Window.Content>
MainPage
public partial class MainWindow : Window
{
CandidatesVM candidatesVM;
public MainWindow()
{
InitializeComponent();
candidatesVM = new CandidatesVM();
this.DataContext = candidatesVM;
}
}
CandidatesVM
public class CandidatesVM
{
public NavigationCandidates navigationCandidates { get; set; }
public CandidatesVM()
{
navigationCandidates = new NavigationCandidates(this);
}
public void Navigate()
{
MainWindow mainWindow = new MainWindow();
mainWindow._CLK.Content = new Candidates();
}
}
NavigationCandidates
public class NavigationCandidates : ICommand
{
public CandidatesVM candidatesVM { get; set; }
public event EventHandler CanExecuteChanged;
public NavigationCandidates(CandidatesVM canVM)
{
candidatesVM = canVM;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
candidatesVM.Navigate();
}
}
Bind to navigationCandidates, that's the command:
<Button x:Name="BtnClk" ... Command="{Binding navigationCandidates}"/>
Then I don't know why you are creating a new instance of the MainWindow in the Navigate() method of CandidatesVM. I guess you want to set the Content of the already existing one:
public class CandidatesVM
{
public NavigationCandidates navigationCandidates { get; set; }
private readonly MainWindow _mainWindow;
public CandidatesVM(MainWindow mainWindow)
{
_mainWindow = mainWindow;
navigationCandidates = new NavigationCandidates(this);
}
public void Navigate()
{
_mainWindow.Content = new Candidates();
}
}
public partial class MainWindow : Window
{
CandidatesVM candidatesVM;
public MainWindow()
{
InitializeComponent();
candidatesVM = new CandidatesVM(this);
this.DataContext = candidatesVM;
}
}
You should be binding to navigationCandidates rather than CandidateVM
<Button HorizontalAlignment="Center" MinHeight="32" MinWidth="120" Foreground="Black" Background="White" Margin="0,10,0,0" Content="Login" FontWeight="Bold" BorderThickness="2"
x:Name="BtnClk" Command="{Binding navigationCandidates }"/>
Why ? CandidateVM is served as a data context to your window. So you should be binding to some property of data context and not to data context itself.

How can I DataBind a textbox from the parent window with values from the child with MVVM?

I just took over a project from another programmer who is no longer here. It was created using the MVVM Pattern (using the MVVM Light toolkit). I am new to MVVM and have been trying to learn the basics fast. Currently I am having trouble getting a selected value from a Child Window back to the Parent Window.
From another post on SO I learned that I should use the same ViewModel for both the parent and the child so I think I have the basics right. However I have not been able to get the selected values back to the parent. Below is a sample set of code similar to the production code.
My ViewModel for both pages is here
public class MainViewModel : ViewModelBase
{
private Vendor selectedVendor = null;
List<Vendor> vendors;
public MainViewModel()
{
OpenVendorWindowCommand = new RelayCommand(VendorSelect);
VendorSelectedCommand = new RelayCommand(VendorSelected);
LoadVendors();
}
public ICommand OpenVendorWindowCommand { get; private set; }
public ICommand VendorSelectedCommand { get; private set; }
void VendorSelect()
{
Messenger.Default.Send(new NotificationMessage("SelectVendor"));
}
public Vendor SelectedVendor
{
get { return selectedVendor; }
set
{
if (selectedVendor != value)
{
selectedVendor = value;
RaisePropertyChanged();
}
}
}
void VendorSelected()
{
Console.WriteLine(SelectedVendor.VendorName);
}
public List<Vendor> Vendors
{
get
{
return vendors;
}
set
{
if (vendors != value)
{
vendors = value;
RaisePropertyChanged();
}
}
}
private void LoadVendors()
{
DataTable dt = new DataTable();
dt = Vendor.GetVendors();
Vendors = new List<Vendor>();
foreach (DataRow row in dt.Rows)
{
Vendors.Add(new Vendor()
{
VendorID = Convert.ToInt32(row["VendorID"]),
VendorCode = Convert.ToString(row["VendorCode"]),
VendorName = Convert.ToString(row["VendorName"])
});
}
}
}
I am at the point that the Child Window opens and I am able to select a vendor from a ListBox. After the selection I press a button (VendorSelectedCommand) and it is at that point I want the textbox on the Parent Window to be filled with the SelectedVendor.VendorName value.
This is the XAML from my Child Window
<StackPanel VerticalAlignment="Center">
<ListBox
Height="200"
Margin="5"
HorizontalAlignment="Stretch"
Background="GhostWhite"
ItemsSource="{Binding Vendors}"
SelectedItem="{Binding Path=SelectedVendor, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Black" BorderThickness="3">
<StackPanel Margin="15">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="175" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
FontWeight="SemiBold"
Foreground="Black"
Text="{Binding VendorName}" />
<TextBlock
Grid.Column="1"
FontWeight="SemiBold"
Foreground="Black">
<Run Text=" (" />
<Run Text="{Binding VendorCode}" />
<Run Text=") " />
</TextBlock>
</Grid>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Command="{Binding VendorSelectedCommand}" Content="Send Vendor Back" />
</StackPanel>
And lastly this is the XAML for the Parent Window with what I think is the correct binding
<StackPanel VerticalAlignment="Center">
<TextBox Margin="10" Text="{Binding SelectedVendor.VendorName}" />
<Button
Margin="10"
Command="{Binding OpenVendorWindowCommand}"
Content="Select Vendor" />
</StackPanel>
I have tried every possible combination of Binding Syntax that I can think of and have tried multiple different ways in the code behind to catch and bind it but have not been able to get it right. What is missing from my ViewModel to make this work?
Edit For clarity (and in response to a comment) I am adding the DataContext, which I had in the Constructor of the Views.
public partial class VendorView : Window
{
private MainViewModel _vm = null;
public VendorView()
{
InitializeComponent();
_vm = new MainViewModel();
DataContext = _vm;
}
}
Edit #2 I am opening the second page with this. This is very simple sample app with only two pages so I didn't want to get bogged down with navigation until I have a better handle on Binding.
private void NotificationMessageReceived(NotificationMessage msg)
{
if (msg.Notification == "SelectVendor")
{
var vendorView = new VendorView();
vendorView.ShowDialog();
}
}

Binding usercontrol inside itemcontrol

I have 2 tasks.
Add a single usercontrol to a parent window.
Add a collection of a usercontrol to a parent window.
I have problem to fulfill task 2 in relation to the data binding and command binding.
if someone knows how to do task 2, please add some code.
This is my implementation for both tasks, in case someone want to fix it.. :
I have a usercontrol called "Book" that contains 3 textblocks and a button.
The userControl has dependecyProperty of my book model and for the button command.
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; }
}
In order to complete task 1 I created a window:
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;
}
Great, Task 1 Completed
https://onedrive.live.com/redir?resid=3A8F69A0FB413FA4!116&authkey=!AHiyrfEnBr2a-rM&v=3&ithint=photo%2cpng
Now, trying to complete task 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);
}
The Binding fail, the button "save" stops respoding.
https://onedrive.live.com/redir?resid=3A8F69A0FB413FA4!121&authkey=!AKnyQk6Ge_9QHug&v=3&ithint=photo%2cpng
So, what is going on ? why binding fail, why the button "save" is not functioning ?
You're not setting your DependencyProperties in the list example.
<DataTemplate>
<Controls:BookControl />
</DataTemplate>
Look at how you did it in your non-list version.
<Controls:BookControl TheBook="{Binding Book}" SomeCommand="{Binding
SaveCommand}" />
That being said, you don't need the DependencyProperties at all, the UserControl will inherit the DataContext for each 'Book' in the list of books as the ItemsControl creates them. You just need to not set the DataContext on the grid.
Then your button could just bind to the BookViewModel command property.
<Button Grid.Row="3" Command="{Binding SaveCommand}" Content="Save" />
If your concern is not knowing what is available for the inherited DataContext, you could do this to get design time support.
d:DataContext="{d:DesignInstance Type=local:BookViewModel,
IsDesignTimeCreatable=False}"
Just make sure that the following is defined somewhere in the file, it usually is by default.
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Update
So I missed the second issue, should have actually fired up Visual Studio. The issue is that your command is in the MainViewModel.cs. That said, our UserControl has inherited the DataContext of each Book object. The short of it is that the button is looking for the command inside of the Book object.
I'm going to assume that since you have a save command that you will be editing the Book object. So let's take this chance to go ahead and make a ViewModel. I'm going to move the save command to there, so that save is always available off of a BookViewModel. There could be good reasons to have the save command somewhere else, but for simplicity's sake, we'll put it in the ViewModel.
Also, I'm not sure if you have INotifyPropertyChanged implemented anywhere, as your MainViewModel and ContainerViewModel don't show that one is used. If you don't, I'd highly recommend you take a step back and look into an implementation or an MVVM framework for your ViewModels.
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;
}
}
That is a very basic example of what you would probably want to do. I wanted to keep it simple to not take away from the example, you will probably want to at least do some null checking.
With the above, you shouldn't have to change your UserControl any, I had to add the row and column definitions, but I ended up with the following:
<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>
Hopefully you noticed that our BookViewModel's constructor accepts a book, so that means that we need to change our ContainerViewModel to house the proper collection and create them correctly.
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;
}
}
}
All that and your ItemsControl can simply be as follows:
<ItemsControl ItemsSource="{Binding Path=Books}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:MyBookControl />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Drop into empty collection with gong-wpf

I am using the wpf component https://github.com/punker76/gong-wpf-dragdrop
in order to do drag and drop, but I cannot seem to be able to drop in a empty collection. If I initialize the collection with one element, it works.
I also created my own drop handler to see what happens, but it is never called for the empty collection. Is there any way of enabling drop to an empty collection?
Sample xaml:
<UserControl.Resources>
<wf:MyDefaultDropHandler x:Key="myDND" />
<HierarchicalDataTemplate ItemsSource="{Binding Instructions}" DataType="{x:Type wf:WhileBlock}">
<TextBlock Text="While" />
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type wf:InstructionsList}">
<ItemsControl ItemsSource="{Binding}"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.UseDefaultDragAdorner="True"
dd:DragDrop.DropHandler="{StaticResource myDND}" />
</DataTemplate>
<DataTemplate DataType="{x:Type wf:IfElseBlock}">
<StackPanel>
<TextBlock Text="If" />
<ContentControl Content="{Binding IfInstructions}" />
<TextBlock Text="Else" />
<ContentControl Content="{Binding ElseInstructions}" />
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border Grid.Column="0">
<ContentControl Content="{Binding AvailableComponents}" />
</Border>
<Border Grid.Column="1"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.DropHandler="{StaticResource myDND}">
<ContentControl Content="{Binding Instructions}" />
</Border>
</Grid>
My view models. If I uncomment the line //Instructions.Add(new IfElseBlock()); drop works as expected
public abstract class AInstruction
{
}
public abstract class ACondition
{
}
public class InstructionsList : ObservableCollection<AInstruction>
{
}
public class WhileBlock : AInstruction
{
private readonly InstructionsList _instructions = new InstructionsList();
public ACondition ExecuteIf { get; set; }
public InstructionsList Instructions { get { return _instructions; } }
}
public class IfElseBlock : AInstruction
{
private readonly InstructionsList _ifInstructions = new InstructionsList();
private readonly InstructionsList _elseInstructions = new InstructionsList();
public ACondition Condition { get; set; }
public InstructionsList IfInstructions { get { return _ifInstructions; } }
public InstructionsList ElseInstructions { get { return _elseInstructions; } }
}
public class Script
{
private readonly InstructionsList _instructions = new InstructionsList();
private readonly InstructionsList _availableComponents = new InstructionsList();
public Script()
{
AvailableComponents.Add(new IfElseBlock());
AvailableComponents.Add(new IfElseBlock());
AvailableComponents.Add(new IfElseBlock());
AvailableComponents.Add(new WhileBlock());
AvailableComponents.Add(new WhileBlock());
AvailableComponents.Add(new WhileBlock());
//Instructions.Add(new IfElseBlock());
}
public InstructionsList Instructions { get { return _instructions; } }
public InstructionsList AvailableComponents { get { return _availableComponents; } }
}
my handler, just to do some debugging
public class MyDefaultDropHandler : DefaultDropHandler
{
public override void DragOver(IDropInfo dropInfo)
{
Debug.WriteLine("DragOver " + dropInfo.TargetItem);
base.DragOver(dropInfo);
}
public override void Drop(IDropInfo dropInfo)
{
Debug.WriteLine("Drop " + dropInfo.TargetItem);
base.Drop(dropInfo);
}
}
It seems there is no hit target because of the transparent background and the size of the control.
I just added Padding="1" MinHeight="10" Background="White" to my ItemsControl and now drop works for empty collections.
In my sample xaml it would look like this:
<ItemsControl ItemsSource="{Binding}" Padding="1" BorderThickness="5,0,0,0"
MinHeight="10"
Background="White"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.UseDefaultDragAdorner="True"
dd:DragDrop.DropHandler="{StaticResource myDND}" />

Prism 4.1 , Silverllight 5 and .Net 4.5.1 DelegateCommant for Button Not working

I'm new to Prism. I'm trying to setup a test project on Prism. I download Prism 4.1 as I found out Prism 5 doesn't work with Silverlight 5 Yet. so My configuration is Like this.
I've visual studio 2013 , Silverlight 5 and .Net 4.5.1. A basic exercise 1 Homepage divided in to 2 parts with 2 Prism module I followed for Hello world example. Done and working 1 Region Hello, 2end Regigon world
Now in Hello Module I create 1 User form. Created 1 Use.cs with INotifyPropertyChanged etc. Followed MVVM. For created Data Appeared in form. Bow I bind 1 Submit button and display change date on the same region.
I used DelegateCommand. Now working .
No Bug shown But No firing of event.
Project Structure is Like this
.Net Silverlight Navigation Application
aprism
Shell.xaml
Bootstrapper.cs
aprism.web
aprism.Hello
HelloView.xaml
HelloView.xamal.cs : UserControl , IHelloView
IHelloView : IView
IHelloViewModel : IViewModel
HelloViewModel : ViewModelBase, IHelloViewModel
aprism.World
aprism.Business
User.cs : INotifyPropertyChanged , IDataErrorInfo
aprism.Infrastructure
IView
IViewModel
ViewMode
public interface IView
{
IViewModel ViewModel { get; set; }
}
public interface IViewModel
{
IView View { get; set; }
}
public class ViewModelBase :IViewModel ,INotifyPropertyChanged
{
public ViewModelBase(IView view) {
View = view;
View.ViewModel = this;
}
public IView View
{
get;
set;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName) {
if (PropertyChanged != null)
{
PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
}
}
}
public class HelloViewModel : ViewModelBase, IHelloViewModel
{
public DelegateCommand SubmitRegistrationForm { get; set; }
public HelloViewModel(View.IHelloView view):base(view)
{
this.View = view;
this.View.ViewModel = this;
this.HelloText = "Prism Hello..";
CreateUse();
//User.PropertyChanged +=User_PropertyChanged;
this.SubmitRegistrationForm = new DelegateCommand(Save, CanSave);
}
/* private void User_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
SubmitRegistrationForm.RaiseCanExecuteChanged();
}*/
private bool CanSave()
{
return true;
}
private void Save()
{
User.DateUpdated = DateTime.Now;
}
#region IHelloViewModel Members
public string HelloText { get; set; }
private User _user;
public User User {
get { return _user; }
set
{
_user = value;
OnPropertyChanged("User");
}
}
private void CreateUse() {
User = new User()
{
Username="Anand",
Email = "akirti.iitk#gmail.com",
Password = "delasoft",
ConfirmPassword = "delasoft"
};
}
/* public Infrastructure.IView View
{
get;
set;
}
*/
#endregion
}
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" x:Class="Hpmsprism.Hello.View.HelloView"
mc:Ignorable="d"
xmlns:local="clr-namespace:Hpmsprism.Business;assembly=Hpmsprism.Business"
xmlns:Commands="clr-namespace:Microsoft.Practices.Prism.Commands;assembly=Microsoft.Practices.Prism"
d:DesignHeight="500" d:DesignWidth="500">
<UserControl.Resources>
<local:User x:Key="cUser"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock Text="{Binding HelloText}" FontSize="26" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="10"/>
<TextBlock HorizontalAlignment="Left" Margin="98,35,0,0"
TextWrapping="Wrap" Text="User Registration"
VerticalAlignment="Top" FontSize="20"/>
<sdk:Label HorizontalAlignment="Left"
Height="28" Margin="110,96,0,0"
VerticalAlignment="Top" Width="90" Content=" User Name : "/>
<sdk:Label HorizontalAlignment="Left"
Height="28" Margin="110,129,0,0"
VerticalAlignment="Top" Width="90" Content=" Email : "/>
<sdk:Label HorizontalAlignment="Left"
Height="28" Margin="110,157,0,0"
VerticalAlignment="Top" Width="90" Content=" Password : "/>
<sdk:Label HorizontalAlignment="Left"
Height="28" Margin="110,204,0,0"
VerticalAlignment="Top" Width="124" Content=" Confirm Password : "/>
<Button Content="Register" HorizontalAlignment="Left" Margin="342,301,0,0"
VerticalAlignment="Top" Width="75" x:Name="SubmitRegisterForm" Commands:Click.Command="{Binding Path=SubmitRegistrationFormCommand}"/>
<TextBox HorizontalAlignment="Left" Height="23" Margin="247,92,0,0"
TextWrapping="Wrap" Text="{Binding User.Username,Mode=TwoWay,ValidatesOnDataErrors=True}" VerticalAlignment="Top" Width="170" x:Name="UserName"
/>
<TextBox HorizontalAlignment="Left" Height="23" Margin="247,125,0,0"
TextWrapping="Wrap" Text="{Binding User.Email,Mode=TwoWay,ValidatesOnDataErrors=True}" VerticalAlignment="Top" Width="170" x:Name="Email"/>
<PasswordBox HorizontalAlignment="Left" Margin="247,157,0,0"
VerticalAlignment="Top" Width="170" x:Name="Password"
Password="{Binding User.Password,Mode=TwoWay,ValidatesOnDataErrors=True}"/>
<PasswordBox HorizontalAlignment="Left" Margin="247,200,0,0"
VerticalAlignment="Top" Width="170" x:Name="ConfirmPassword"
Password="{Binding User.ConfirmPassword,Mode=TwoWay,ValidatesOnDataErrors=True}"/>
<sdk:Label HorizontalAlignment="Left" Height="28" Margin="110,257,0,0"
VerticalAlignment="Top" Width="120" Content=" Date Updated :"/>
<TextBlock HorizontalAlignment="Left" Margin="230,257,0,0" TextWrapping="Wrap"
Text="{Binding User.DateUpdated}" VerticalAlignment="Top" x:Name="DateUpdated"/>
</Grid>
</UserControl>
My Button Doesn't fire Submit Command.
PLease Help me.
Thank you
Finally I got It working. After Polishing my MVVM Concept & Unity Again.
Problem is Any Property used in HelloViewModel should have the signature in IHelloViewModel Interface too. And for this Property I Need to Implement INotifyPropertyChanged too.
So I did Like this :
private DelegateCommand _command;
public DelegateCommand SubmitRegistrationFormCommand
{
get { return _command; }
set { _command = value; OnPropertyChanged("SubmitRegistrationFormCommand"); }
}
// This in Implementation
and In Interface I had a Property Signature to Like this
DelegateCommand SubmitRegistrationFormCommand{set;get;}
This may be When Ioc Loads & Map this interface is the role play Thing as DataContext is of Type this ViewModel after Setting the Property
http://social.msdn.microsoft.com/Forums/en-US/531eb18f-3060-4adf-a44e-8dffe0fcbd07/prism-41-silverlight-5-with-net-451-delegatecommand-not-working?forum=wpf
Initially Didn't work for me until I didn't mapped my Interface.

Resources