Silverlight ItemsControl. Can you remove the panel completely via templating? - silverlight

I have a DataTamplate for my ItemsControl that merely contains an Image with some other meta data. What I am trying to do is bind to the ItemsControl and have the Images be displayed with the Convas.Left and Canvas.Top that is bound via the data I give.
I have been trying my best to remove any Panels from the control via the ItemsPanelTemplate, so I can use the Attached Properties in the parent canvas, but it seems that you will always get a StackPanel by default.
Anyone out there have any good ideas?
Thanks,
Dave

The layout of items in an ItemsControl is controlled via the ItemsControl.ItemsPanel property which is of type ItemsPanelTemplate. The default value for the ItemsControl.ItemsPanel property is indeed an instance of ItemsPanelTemplate that specifies a StackPanel but this is completely customizable.
The code example (on this MSDN page) shown below the paragraph that starts "The following example creates an ItemsControl." is very useful in understanding what the ItemsControl.Template, ItemsControl.ItemsPanel and ItemsControl.ItemTemplate properties are for.
There are a few ways to achieve what you describe in the second sentence of the first paragraph of your question. Here is a full example:
Page.xaml:
<UserControl x:Class="ItemsControlImages.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:app="clr-namespace:ItemsControlImages">
<UserControl.Resources>
<DataTemplate x:Key="CountryTemplate">
<Canvas>
<Image Canvas.Top="{Binding Location.Y}"
Canvas.Left="{Binding Location.X}"
Source="{Binding FlagImage}" />
<StackPanel Canvas.Top="{Binding Location.Y}"
Canvas.Left="{Binding Location.X}">
<TextBlock Text="{Binding Title}" />
<TextBlock Text="{Binding Location}" />
<StackPanel.RenderTransform>
<TranslateTransform Y="-32.0" />
</StackPanel.RenderTransform>
</StackPanel>
</Canvas>
</DataTemplate>
</UserControl.Resources>
<Canvas x:Name="LayoutRoot">
<Canvas.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFB2C6D5"/>
<GradientStop Color="#FF1483D9" Offset="1"/>
</LinearGradientBrush>
</Canvas.Background>
<ItemsControl ItemTemplate="{StaticResource CountryTemplate}">
<app:Country Title="Argentina" Location="56,218" FlagImage="Images/ARG.png" />
<app:Country Title="China" Location="368,66" FlagImage="Images/CHN.png" />
<app:Country Title="Ireland" Location="192,90" FlagImage="Images/IRE.png" />
<app:Country Title="New Zealand" Location="404,225" FlagImage="Images/NZ.png" />
<app:Country Title="United States" Location="40,80" FlagImage="Images/USA.png" />
</ItemsControl>
</Canvas>
</UserControl>
Country.cs:
using System.ComponentModel;
using System.Windows;
namespace ItemsControlImages
{
public class Country : INotifyPropertyChanged
{
private string title;
private string flagImage;
private Point location;
public string Title
{
get
{
return this.title;
}
set
{
if ((object.ReferenceEquals(this.title, value) != true))
{
this.title = value;
this.RaisePropertyChanged("Title");
}
}
}
public string FlagImage
{
get
{
return this.flagImage;
}
set
{
if ((object.ReferenceEquals(this.flagImage, value) != true))
{
this.flagImage = value;
this.RaisePropertyChanged("FlagImage");
}
}
}
public Point Location
{
get
{
return this.location;
}
set
{
if ((this.location.Equals(value) != true))
{
this.location = value;
this.RaisePropertyChanged("Location");
}
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if (propertyChanged != null)
{
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
}
That's all you need (along with the images in an Images folder) for this end result:
alt text http://www.freeimagehosting.net/uploads/bec683b75e.png
Note even though the Images are in an ItemsControl they are positioned at the coordinates shown by binding the Left and Top attached properties of their parent Canvas to the value of the X and Y coordinates from the custom Location property.
For more information on this sample and customizing the ItemsControl using templates in general you can check out this blog post.

Related

WPF: Placing game pieces on board

I'm currently creating a board game in WPF. I'm creating my board in my PlayerViewModel so I have a nice 10x10 board. I also create pieces that the player starts with (4). Here is where I get stuck, because I'm not quite sure if it's possible to just put the player's pieces in my GamePiece.xaml the way I've done it since this is the "component" that creates the whole board for me. The circle/image is the component I want as a player's disc.
I bind this into my GameView.xaml, however the problem is that I want to have circles as my pieces in the game. Obviously here I'm just creating the whole board and so it's also creating the pieces (circles/photos) and I can't seem to manipulate this and decide how many I want to show on the board in the beginning. I have tried different ways, like put the pieces on specific coordinates and just having the color of the square it's taking up on the board change, but it doesn't look very nice.
First, you would create a ListView and configure it to place the items in rows (by using WrapPanel as ItemsPanel and setting the width and height for the ListView), and -as you mentioned- you can use BoardPiece UserControl as ItemTemplate.
Your GameView.xaml can be something similar to this
<UserControl
x:Class="GameView">
<StackPanel Orientation="Vertical">
<ListView
Width="600"
Height="500"
ItemsSource="{Binding BoardPieces}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<testingThings:BoardPiece Margin="0" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button
Width="100"
Margin="8"
Click="ButtonBase_OnClick"
Content="Fill All" />
</StackPanel>
</UserControl>
Then, Configure the ViewModel: create your items and store them in an ObservableCollection to bind them later with the ListView..
public class GameViewViewModel
{
public ObservableCollection<BoardPieceItem> BoardPieces { set; get; } =
new ObservableCollection<BoardPieceItem>();
public GameViewViewModel()
{
for (var i = 0; i < 10; i++)
for (var j = 0; j < 10; j++)
{
// random coloring at initialization, do it as you want..
BoardPieces.Add(new BoardPieceItem
{
Index = (i, j),
RectangleColor = "#00FF00", // green
EllipseColor = (i + j) % 2 == 0
? "#00FFFFFF" // transparent
: "#000000", // Black
});
}
}
}
Now, Bind the ViewModel with the View
public partial class GameView
{
public GameView()
{
InitializeComponent();
DataContext = new GameViewViewModel();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
if (sender is Button { DataContext: TestDialogVm vm })
{
foreach (var item in vm.BoardPieces)
{
item.EllipseColor = "#0000FF";
}
}
}
}
In BoardPiece.xaml there is no need to use Converters
<UserControl
x:Class="SharedModule.Views.TestLab.BoardPiece"
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:testLab="clr-namespace:SharedModule.Views.TestLab"
d:DataContext="{d:DesignInstance testLab:BoardPieceItem}"
MouseDown="UIElement_OnMouseDown"
mc:Ignorable="d">
<Grid>
<Rectangle
Width="45"
Height="45"
Fill="{Binding RectangleColor}"
Stroke="Black"
StrokeThickness="1.3" />
<Ellipse
Width="20"
Height="20"
Fill="{Binding EllipseColor}" />
</Grid>
</UserControl>
Finally, Configure the BoardPieceItem to make it possible to update the game board at runtime..
public class BoardPieceItem : INotifyPropertyChanged
{
public (int, int) Index { get; set; }
private string _rectangleColor;
public string RectangleColor
{
get => _rectangleColor;
set
{
_rectangleColor = value;
OnPropertyChanged();
}
}
private string _ellipseColor;
public string EllipseColor
{
get => _ellipseColor;
set
{
_ellipseColor = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Now you are all set, see how UIElement_OnMouseDown will update the item's color, and ButtonBase_OnClick will update the cells of the board at all (I could go all the way MVVM, but used some events in a hurry).
This is how the game looks like at my side

Is it possible to load and unload usercontrol using triggers only in WPF

I am trying to create MDI kind of functionality whereby I want to load a user control corresponding to the button clicked by user and unload the rest. Every button is associated with a userControl
<Button Content="Worker registration"/> //UserControl1
<Button Content="Worker recognition"/> //UserControl2 ...and so on
<Grid x:Name="UserControlManager"/>
Any reason not to use a tabcontrol? Like this
<TabControl>
<TabItem Header="Control A">
<local:ControlA/>
</TabItem>
<TabItem Header="Control B">
<local:UserControlB/>
</TabItem>
</TabControl>
Or bind all items using the ItemsSource
<TabControl ItemsSource="{Binding MyItems}"/>
There are also third party TabControls that's quite nice, like the one devcomponents provides.
If a TabControl does not suffice (tons of issues I know), you could use a IValueConverter that would convert some property to a view. You could use a Mediator and/or ViewModelLocator, I love MVVM Light from Galasoft. They provide everything through nuget, and even sets up everything for you :)
Add a command for your buttons for selecting the content you want to show. And add the xaml for showing the SelectedControl.
Bad mediator / ViewmodelLocator ;) Use I.E. Galasofts instead like in this post
public class ViewModelLocator : INotifyPropertyChanged
{
private UserControl selectedControl;
private ObservableCollection<UserControl> controls = new ObservableCollection<UserControl>();
public UserControl SelectedControl
{
get { return selectedControl; }
set
{
if (Equals(selectedControl, value)) return;
selectedControl = value;
OnPropertyChanged();
}
}
public ObservableCollection<UserControl> Controls
{
get { return controls; }
set
{
if (Equals(controls, value)) return;
controls = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Hope it helps!
Cheers
Stian
You can use DataTemplates to load views depending on what data (viweModel) you set
<Window.Resources>
<ResourceDictionary>
<DataTemplate DataType="{x:Type viewModel:ViewModel1}">
<view:View1 />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModel:ViewModel2}">
<view:View2 />
</DataTemplate>
</ResourceDictionary>
</Window.Resources>
Then have a ContentControl where your content will show
<Grid >
<ContentControl Content="{Binding MyContent}" />
</Grid
Use an enumBooleanConverter (How to bind RadioButtons to an enum?) to select a enum with radiobuttons
<RadioButton GroupName="Navigation"
IsChecked="{Binding Path=SelectedNavigationEnum,
Converter={StaticResource enumBooleanConverter},
ConverterParameter={x:Static viewModel:NavigationEnum.EnumValue1},
Mode=TwoWay}">Show View1</RadioButton>
<RadioButton GroupName="Navigation"
IsChecked="{Binding Path=SelectedNavigationEnum,
Converter={StaticResource enumBooleanConverter},
ConverterParameter={x:Static viewModel:NavigationEnum.EnumValue2},
Mode=TwoWay}">Show View2</RadioButton>
When the SelectedNavigationEnum property is changed set the MyContent property to the selected viewModel
public NavigationEnum SelectedNavigationEnum
{
...
set
{
...
Navigate(value);
}
}
protected void Navigate(NavigationEnum part)
{
switch (part)
{
case NavigationEnum.EnumValue1:
ShowView1();
break;
case NavigationEnum.EnumValue2:
ShowView2();
...
}
}
private void ShowView1()
{
ViewModel1 viewModel = ObjectFactory.GetInstance<ViewModel1>();
MyContent = viewModel;
}
When you set MyContent the DataTemplate will load View1 and set the viewModel as its DataContext.

How to close a TabItem in MVVM Light

In my view i'm adding dynamically custom TabItems (TextseiteTabItem). With the property DataContext i gave each TabItem a Model to work with (fill in values). Now i added a close-command to the custom TabItems but it wont work. I cant manage to send the close-command to the viewmodel. Above is my attempt..
My custom TabItem:
<sdk:TabItem x:Class="PortfolioCreator.TextseiteTabItem"
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"
mc:Ignorable="d"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit">
<sdk:TabItem.Header>
<StackPanel Orientation="Horizontal">
<sdk:Label Content="{Binding Seitennummer, StringFormat='Seite {0}', Mode=TwoWay}"/>
<Button Content="X"
Command="{Binding CloseTabCommand, Mode=TwoWay}"
DataContext="{Binding ElementName=TemplateTabControl}"
CommandParameter="{Binding SelectedItem, ElementName=TemplateTabControl}" />
</StackPanel>
</sdk:TabItem.Header>
<sdk:TabItem.Content>
<Grid x:Name="LayoutRoot">
...
</Grid>
</sdk:TabItem.Content>
</sdk:TabItem>
In my View:
...
<sdk:TabControl toolkit:DockPanel.Dock="Bottom" ItemsSource="{Binding Tabs}" x:Name="TemplateTabControl"/>
...
In my ViewModel:
public class PortfolioViewModel : ViewModelBase
{
public ObservableCollection<TabItem> Tabs { get; set; }
public RelayCommand<TabItem> CloseTabCommand
{
get;
private set;
}
public PortfolioViewModel()
{
CloseTabCommand = new RelayCommand<TabItem>(tab =>
{
//never reached
},
tab =>
{
//never reached
});
Tabs = new ObservableCollection<TabItem>();
AddTextseite();
AddTextseite();
}
void AddTextseite()
{
TabItem item = new TextseiteTabItem();
item.DataContext = new TextSeiteModel();
Tabs.Add(item);
}
}
First, your CloseTabCommand does nothing in your current code snippet: //never reached. The execute handler should read something like tab.Visibility = Visibility.Collapsed or myTabControl.Items.Remove(myTabItem).
Second, as #Rafal pointed out, using UI elements in the ViewModel is not the correct way to implement MVVM. If you want closable tab items, the correct way would be to derive a generic CloseableTabItem control or write a ClosableTabItemBehavior on the UI layer with a settable ICommand CloseCommand that can be bound to the corresponding ICommand instance on the ViewModel. Admittedly this approach might be too elaborate for your project though.
You are attempting to use MVVM but the strange thing I see is collection of ui elements (Tabs) in your view model. The correct way would be to create ViewModel that describes Tab item and move the command there. Then it will bind. To remove tab from Tabs you should expose event in your Tab view model and attach to it form PortfolioViewModel.
Of course my change will cause that your TextseiteTabItem will not show in TablControl. But it can be easily fixed with TabControl.ItemTemplate and TabControl.ContentTemplate.
here you find a demo application with closeable tabs for wpf, maybe it works for your silverlight version also.
This is my workaround for this problem. I admit it is not a good solution and breaks the mvvm pattern but as #herzmeister says other approaches are too elaborate for my project right now. (But it won't be the final solution ;-) )
TabItemViewModel:
public delegate void CloseTabItemHandler();
public class TextseiteTabItemViewModel : ViewModelBase
{
public event CloseTabItemHandler CloseTabItem;
public RelayCommand CloseTabCommand {get; set;}
public TextseiteTabItemViewModel()
{
CloseTabCommand = new RelayCommand(() =>
{
if (CloseTabItem == null) return;
CloseTabItem();
});
}
}
TabItemView:
<sdk:TabItem x:Class="PortfolioCreator.TextseiteTabItemView"
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"
mc:Ignorable="d"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit">
<sdk:TabItem.Header>
<StackPanel Orientation="Horizontal">
<Button Content="X" Command="{Binding CloseTabCommand, Mode=TwoWay}" />
</StackPanel>
</sdk:TabItem.Header>
<sdk:TabItem.Content>
<Grid x:Name="LayoutRoot">
...
</Grid>
</sdk:TabItem.Content>
</sdk:TabItem>
Parent ViewModel:
public class PortfolioViewModel : ViewModelBase
{
public ObservableCollection<TabItem> Tabs { get; set; }
public PortfolioViewModel()
{
Tabs = new ObservableCollection<TabItem>();
AddTextseite();
AddTextseite();
}
void AddTextseite()
{
var viewmodel = new TextseiteTabItemViewModel();
TabItem item = new TextseiteTabItemView();
item.DataContext = viewmodel;
viewmodel.CloseTabItem += new CloseTabItemHandler(() =>
{
Tabs.Remove(item);
});
Tabs.Add(item);
}
}

How do I properly wire up visibility binding on a grid using Silverlight MVVM pattern?

More specifically, am I doing it right because it is not working. I have a bool property in my ViewModel along with a text property for a TextBlock. If I change the text property, the results appear on screen immediately. So I know something is listening for the property changes. The visibility property is set to use a bool-to-visibility converter but that converter never gets called. I'm sure it is just some part of the data binding that I am not doing right but I have tried everything suggested on StackOverflow as well as setting the binding manually and several other things. I have over 12 hours in this problem and am feeling really let down by the whole Silverlight / MVVM architecture in general. And I was so excited that I "figured it out", too.
Particulars: Silverlight 5.1.10144
App.xaml resources:
<Application.Resources>
<vidstreams:ManagementViewModel x:Key="managementViewModel"/>
<vidstreams:VisibilityConverter x:Key="visConverter"/>
</Application.Resources>
MyView.xaml DataContext:
<UserControl.DataContext>
<Binding Source="{StaticResource managementViewModel}"/>
</UserControl.DataContext>
MyView.xaml Grid visibility binding:
<Grid x:Name="LayoutRoot" Background="Black">
<Grid.RowDefinitions>
<RowDefinition Height="60"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid ...
Visibility="{Binding IsWaitingVisible, Mode=OneWay, Converter={StaticResource visConverter}}">...</Grid>
<Button x:Name="test"
Click="test_Click"
Content="test visibility"
HorizontalAlignment="Left"
Margin="0,0,0,0"
Grid.Row="1"
VerticalAlignment="Top"/>
</Grid>
MyView.xaml.cs Instance property and test_Click code:
public ManagementViewModel DataContextObject
{
get
{
return (ManagementViewModel)App.Current.Resources["managementViewModel"];
}
}
protected void test_Click(object sender, RoutedEventArgs e)
{
DataContextObject.IsWaitingVisibile = !DataContextObject.IsWaitingVisibile; //doesn't toggle the visibility or cause the converter to be hit
DataContextObject.WaitingText = "Loading data..."; //works
}
ManagementViewModel class innards:
public class ManagementViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
var p = PropertyChanged;
if (p != null)
{
p(this, new PropertyChangedEventArgs(propertyName));
}
}
bool mIsWaitingVisible = true;
public bool IsWaitingVisibile
{
get { return mIsWaitingVisible; }
set
{
mIsWaitingVisible = value;
OnPropertyChanged("IsWaitingVisible");
}
}
...
}
I would post the converter code here but it isn't even being hit. It's a simple converter like the others found in various posts on this site, anyway.
Any thoughts or suggestions - or just confirmation that this is some sort of regression bug in 5 maybe? - would be so appreciated. Perhaps the visibility binding instructions have to be set differently. Remember, the TextBlock works fine:
<TextBlock x:Name="WaitingTextBlock"
Text="{Binding WaitingText}" .../>
#GolfARama
Hi can you try with this
Visibility="{Binding IsWaitingVisible, Mode=TwoWay, Converter={StaticResource visConverter}}">

Only update a DataGrid binding the first time

I have a view with a button and a dataGrid. The XAML file is this:
<Window x:Class="MusicaDB.Views.PrincipalView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
Title="Principal" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" d:DesignHeight="627" d:DesignWidth="1176" SizeToContent="WidthAndHeight">
<Window.Resources>
<DataTemplate x:Key="BlueHeader">
<StackPanel Orientation="Horizontal" Margin="-5,-5,-5,-5" Width="120">
<StackPanel.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF223B84" Offset="1"/>
<GradientStop Color="#FF57A0F4" Offset="0.5"/>
<GradientStop Color="#FF4B94EC" Offset="0.5"/>
</LinearGradientBrush>
</StackPanel.Background>
<TextBlock Margin="10,10,10,10" Text="{Binding}" VerticalAlignment="Center" Foreground="White"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Button Content="Search"
Height="23"
HorizontalAlignment="Left"
Margin="12,165,0,0"
Name="btnPersonSearch"
VerticalAlignment="Top"
Width="48">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction
Command="{Binding PersonSearch}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Grid Height="558" Width="1099">
<DataGrid
Height="164"
HorizontalAlignment="Left"
Margin="339,24,0,0"
Name="dgdAutores"
VerticalAlignment="Top"
Width="540"
IsTextSearchEnabled="True"
CanUserAddRows="True"
CanUserDeleteRows="True"
ItemsSource="{Binding DgdPersons}">
<DataGrid.Columns>
<DataGridTextColumn Header="IDPerson" Binding="{Binding IDPerson}"></DataGridTextColumn>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
In my ViewModel.cs I have two properties, one for the binding and other for the command.
`
private ObservableCollection<Persons> _dgdPersons;
public ICommand _personsSearch { get; set; }
public ObservableCollection<Persons> DgdPersons
{
get { return _dgdPersons; }
set
{
_dgdPersons = value;
base.RaisePropertyChangedEvent("DgdPersons");
}
}
public ICommand PersonsSearch
{
get{return _personsSearch;}
}`
This is the code that I use to search persons, in which I update Persons:
using System;
using System.Windows.Input;
using PersonsDB.ViewModel;
using System.Collections.ObjectModel;
using PersonsDB.DBModels;
using System.Windows.Controls;
namespace MusicaDB.Commands
{
public class AutoresBuscarCommand : ICommand
{
private ViewModelMain _ViewModel;
public PersonsSearchCommand(ViewModelMain viewModel)
{
_ViewModel = viewModel;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(Object parameter)
{
_ViewModel.DgdPersons = _ViewModel.DBManager.getPersons("Parameters of serach");
}
}
}
NOTE: DBManager is a class that let me access to the database. This class internaly use EF 4.1 and the method getPersons returns context.Persons.Local.
This Command class inherit from a base class:
using System.ComponentModel;
namespace PersonsDB.ViewModel
{
public abstract class ViewModelBase : INotifyPropertyChanging, INotifyPropertyChanged
{
public event PropertyChangingEventHandler PropertyChanging;
public event PropertyChangedEventHandler PropertyChanged;
public virtual bool IgnorePropertyChangeEvents { get; set; }
public virtual void RaisePropertyChangedEvent(string propertyName)
{
// Exit if changes ignored
if (IgnorePropertyChangeEvents) return;
// Exit if no subscribers
if (PropertyChanged == null) return;
// Raise event
var e = new PropertyChangedEventArgs(propertyName);
PropertyChanged(this, e);
}
public virtual void RaisePropertyChangingEvent(string propertyName)
{
// Exit if changes ignored
if (IgnorePropertyChangeEvents) return;
// Exit if no subscribers
if (PropertyChanging == null) return;
// Raise event
var e = new PropertyChangingEventArgs(propertyName);
PropertyChanging(this, e);
}
}
}
Well, for not to put a lot of code, I have other class, PersonsSearchCommand that execute the command. This command, also, use other class to request data from the DataBase. This class use EF 4.1 and return context.Persons.Local. This return is what I set the ObservableCollection Persons of the ModelView.
This works, at least and the first time I click the button. The rest of the times the dataGrid does not receive data, does not binding the new results.
I try, in my command class, first, clear the ObservableCollection persons with the clear() method, create a temporal ObservableCollection to receive the return Persons.Local and use a foreach with this temporal ObservableCollection to add its elements to the ObservableCollection Persons to detect new changes, but this doesn`t work. I know that this a bad solution, because if the local has a lot of elements, it could be very slow, but it was to see if I get to update the dataGrid, but not.
Why is it only works the first time?
Thanks.
Daimroc.
EDIT: I have added new code.
EDIT 2: Solved.
Well, finally I found the error. The problem is not of the binding, it's my fault, because I have converted the code from CodeBehind to the MVVM and I am modifying the ItemsSorce in the code-behind too.
I do not realized that the button to clear the search criteria changed the dataGrid from the code-behind and then the itemsSource changed in a way not anticipated.
I have now created a new command for the button clean and works as it should be.
Thank you very much for your help. Daimroc.
I haven't read all of your code, but off the top of my head, why are you using an interaction trigger rather than just using the Command property of the button? That might be the first thing you try.

Resources