I'm learning WPF and I try to update file value of "last modified" or "size" using button "replace", if something is changed values update.
When I use "replace" how can I choose only one of files, only the file that is next to the button not all of them? I don't want to extract that.
I try to do it with commandParameter but it still doesn't work.
xaml:
<Window x:Class="ExerciseRPPX.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:viewmodel="clr-namespace:ExerciseRPPX.ViewModel" d:DataContext="{d:DesignInstance Type=viewmodel:MainWindowViewModel}"
mc:Ignorable="d"
Title="Unzip RPPX" Height="450" Width="800">
<DockPanel Margin="10">
<Button Name="btnOpenFile" Command="{Binding Browse}">Open file</Button>
<ListBox ItemsSource="{Binding AllFiles, UpdateSourceTrigger=PropertyChanged}" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding FileName, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Text="{Binding Modify, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Text="{Binding Size, UpdateSourceTrigger=PropertyChanged}" />
<Button Command="{Binding Open}">Open</Button>
<Button Command="{Binding Replace}" CommandParameter="{Binding FileName}">Replace</Button>
<Button Command="{Binding Delete}">Remove</Button>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
</Window>
ViewModel Command:
public ICommand Replace
{
get
{
return this.replaceCommand ?? (this.replaceCommand = new ButtonCommand((param) =>
{
this.repository.ReplaceEntry(targetPath);
foreach (var fileModel in this.repository.AllEntries)
{
this.AllFiles.Add(new FileViewModel(fileModel));
}
this.RaisePropertyChanged(nameof(this.AllFiles));
},
param => true));
}
}
Model - ReplaceEntry
public void ReplaceEntry(string sourcePath)
{
var infoList = new List<RPPXFileEntry>();
{
using (ZipArchive archive = ZipFile.OpenRead(sourcePath))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
if (entry.FullName.Equals( ), StringComparison.OrdinalIgnoreCase))
{
}
}
}
}
return infoList;
}
Related
I have a tree view nicely connected to my model with a MVVM pattern. I'm running into an issue with the context menu. I do not know how to bind to an element outside the tree. I have created a sample that demonstrates what I'm trying. I hope someone explain to me what I'm doing wrong.
In the sample I have five TextBlocks in the header, each binding differently to the data. And I have a context menu with five entries, again binding differently. The commentary says which binding works and which doesn't. There's even a difference between the header and the context menu.
Some bindings try to bind to another element in the UI another to a property in the view model.
Here's the XAML:
<Window x:Class="WpfApp7_TreeView.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:WpfApp7_TreeView"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800"
x:Name="root">
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding SomeProperty}" /> <!-- ok -->
<TextBlock Grid.Row="1" Text="Text from XAML" x:Name="tb" /> <!-- ok -->
<TreeView Grid.Row="2" HorizontalAlignment="Stretch" ItemsSource="{Binding Departments}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:Department}">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="5" Text="{Binding DepartmentName }" /> <!-- ok -->
<TextBlock Margin="5" Text="{Binding ElementName=tb, Path=Text}"/> <!-- ok -->
<TextBlock Margin="5" Text="{Binding SomeProperty}"/> <!-- no show -->
<TextBlock Margin="5" Text="{Binding ElementName=root, Path=DataContext.SomeProperty}"/> <!-- ok -->
<TextBlock Margin="5" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window},
Path=DataContext.SomeProperty}"/> <!-- ok -->
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Header="Some command" /> <!-- ok -->
<MenuItem Header="{Binding ElementName=tb, Path=Text}" /> <!-- no show -->
<MenuItem Header="{Binding SomeProperty}" /> <!-- no show -->
<MenuItem Header="{Binding ElementName=root, Path=DataContext.SomeProperty}"/> <!-- no show -->
<MenuItem Header="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window},
Path=DataContext.SomeProperty}" /> <!-- no show -->
</ContextMenu>
</StackPanel.ContextMenu>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
And here's the view model:
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace WpfApp7_TreeView
{
public class MainWindowViewModel : ViewModelBase
{
private string someProperty = "Text from the viewmodel";
public string SomeProperty
{
get { return someProperty; }
set { someProperty = value; OnPropertyChanged("SomeProperty"); }
}
public MainWindowViewModel()
{
Departments = new List<Department>()
{
new Department("Department 1"),
new Department("Department 2")
};
}
private List<Department> departments;
public List<Department> Departments
{
get {return departments; }
set { departments = value; OnPropertyChanged("Departments"); }
}
}
public class Department : ViewModelBase
{
public Department(string depname)
{
DepartmentName = depname;
}
public string DepartmentName { get; set; }
}
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propname)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propname));
}
}
}
}
TreeViewItem DataContexts get set to their list item, so the SomeProperty binding in the parent HierarchicalDataTemplate needs to use a RelativeSource binding instead. Change this:
<TextBlock Margin="5" Text="{Binding SomeProperty}"/> <!-- no show -->
... to this:
<TextBlock Margin="5" Text="{Binding DataContext.SomeProperty, RelativeSource={RelativeSource AncestorType=TreeView}}"/>
With respect to your ContextMenu, you are correct in noting that bindings have to be part of the visual tree. The solution to this is to bind via an intermediate Binding Proxy instead. Generally speaking you would bind to the parents DataContext, rather than directly to another control, but it can be done both ways:
<TreeView Grid.Row="2" HorizontalAlignment="Stretch" ItemsSource="{Binding Departments}">
<TreeView.Resources>
<local:BindingProxy x:Key="TextBlockProxy" Data="{Binding Text, ElementName=tb}" />
<local:BindingProxy x:Key="MainViewModelProxy" Data="{Binding}" />
</TreeView.Resources>
<TreeView.ItemTemplate>
...etc...
And then in the ContextMenu:
<!-- Binds to the TextBlock's Text property -->
<MenuItem Header="{Binding Data, Source={StaticResource TextBlockProxy}}" />
<!-- Binds to the main view model's SomeProperty -->
<MenuItem Header="{Binding Data.SomeProperty, Source={StaticResource MainViewModelProxy}}" />
I'm able to bind a collection of my own type to a menu. But I'm struggling with the hotkeys. Either the hotkeys show up but don't work or the hotkeys don't show up but work.
Do you have any idea what goes wrong here?
Here is the stripped-down code:
public class Category : DependencyObject
{
public string Caption
{
get { return (string)GetValue(CaptionProperty); }
set { SetValue(CaptionProperty, value); }
}
public static readonly DependencyProperty CaptionProperty =
DependencyProperty.Register("Caption", typeof(string), typeof(Category), new PropertyMetadata(null));
public ObservableCollection<Item> SubItems
{
get { return (ObservableCollection<Item>)GetValue(SubItemsProperty); }
set { SetValue(SubItemsProperty, value); }
}
public static readonly DependencyProperty SubItemsProperty =
DependencyProperty.Register("SubItems", typeof(ObservableCollection<Item>), typeof(Category), new PropertyMetadata(null));
}
public class Item : DependencyObject
{
public string Header
{
get { return (string)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register("Header", typeof(string), typeof(Item), new PropertyMetadata(null));
}
public class MenuViewModel : DependencyObject
{
public ObservableCollection<Category> MenuCategories
{
get { return (ObservableCollection<Category>)GetValue(MenuCategoriesProperty); }
set { SetValue(MenuCategoriesProperty, value); }
}
public static readonly DependencyProperty MenuCategoriesProperty =
DependencyProperty.Register("MenuCategories", typeof(ObservableCollection<Category>), typeof(MenuViewModel), new PropertyMetadata(null));
public MenuViewModel()
{
MenuCategories = new ObservableCollection<Category>()
{
new Category() {Caption = "_One", SubItems = new ObservableCollection<Item>() { new Item() { Header = "_one"}, new Item() { Header = "t_wo" }, new Item() { Header = "_three" } } },
new Category() {Caption = "_Two", SubItems = new ObservableCollection<Item>() { new Item() { Header = "_one"}, new Item() { Header = "t_wo" }, new Item() { Header = "_three" } } },
};
}
}
public partial class Test1Window : Window
{
public Test1Window()
{
InitializeComponent();
DataContext = new MenuViewModel();
}
}
public class MenuItemContainerTemplateSelector : ItemContainerTemplateSelector
{
public override DataTemplate SelectTemplate(object item, ItemsControl parentItemsControl)
{
var key = new DataTemplateKey(item.GetType());
return (DataTemplate)parentItemsControl.FindResource(key);
}
}
And the xaml 1. try:
<Window x:Class="DynamicMenuTest.Test1Window"
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:DynamicMenuTest"
mc:Ignorable="d"
Title="Test1Window" Height="300" Width="300">
<Window.Resources>
<local:MenuItemContainerTemplateSelector x:Key="MenuItemContainerTemplateSelector"/>
<DataTemplate DataType="{x:Type local:Item}">
<MenuItem Header="{Binding Header}">
<MenuItem.HeaderTemplate>
<DataTemplate>
<AccessText VerticalAlignment="Center" Text="{Binding}" />
</DataTemplate>
</MenuItem.HeaderTemplate>
</MenuItem>
</DataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:Category}" ItemsSource="{Binding SubItems}">
<MenuItem VerticalContentAlignment="Center">
<!-- Hotkey works but doesn't show up -->
<MenuItem.Header>
<AccessText Text="{Binding Caption}"/>
</MenuItem.Header>
</MenuItem>
</HierarchicalDataTemplate>
</Window.Resources>
<Grid>
<Menu ItemsSource="{Binding MenuCategories}"
UsesItemContainerTemplate ="true"
ItemContainerTemplateSelector="{StaticResource MenuItemContainerTemplateSelector}"
/>
</Grid>
Xaml 2. try:
<Window x:Class="DynamicMenuTest.Test2Window"
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:DynamicMenuTest"
mc:Ignorable="d"
Title="Test2Window" Height="300" Width="300">
<Window.Resources>
<local:MenuItemContainerTemplateSelector x:Key="MenuItemContainerTemplateSelector"/>
<DataTemplate DataType="{x:Type local:Item}">
<MenuItem Header="{Binding Header}">
<MenuItem.HeaderTemplate>
<DataTemplate>
<AccessText VerticalAlignment="Center" Text="{Binding}" />
</DataTemplate>
</MenuItem.HeaderTemplate>
</MenuItem>
</DataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:Category}" ItemsSource="{Binding SubItems}">
<MenuItem
Header="{Binding Caption}"
VerticalContentAlignment="Center">
<!-- Hotkey shows up but menu not working -->
<MenuItem.HeaderTemplate>
<DataTemplate>
<ContentPresenter RecognizesAccessKey="True" Content="{Binding }" VerticalAlignment="Center" Margin="4,0"/>
</DataTemplate>
</MenuItem.HeaderTemplate>
</MenuItem>
</HierarchicalDataTemplate>
</Window.Resources>
<Grid>
<Menu ItemsSource="{Binding MenuCategories}"
UsesItemContainerTemplate ="true"
ItemContainerTemplateSelector="{StaticResource MenuItemContainerTemplateSelector}"
/>
</Grid>
Xaml 3. try:
<Window x:Class="DynamicMenuTest.Test3Window"
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:DynamicMenuTest"
mc:Ignorable="d"
Title="Test3Window" Height="300" Width="300">
<Window.Resources>
<local:MenuItemContainerTemplateSelector x:Key="MenuItemContainerTemplateSelector"/>
<DataTemplate DataType="{x:Type local:Item}">
<MenuItem Header="{Binding Header}">
<MenuItem.HeaderTemplate>
<DataTemplate>
<AccessText VerticalAlignment="Center" Text="{Binding}" />
</DataTemplate>
</MenuItem.HeaderTemplate>
</MenuItem>
</DataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:Category}" ItemsSource="{Binding SubItems}">
<MenuItem
Header="{Binding Caption}"
VerticalContentAlignment="Center">
<!-- Hotkey shows up but menu doesn't work -->
<MenuItem.HeaderTemplate>
<DataTemplate>
<AccessText Text="{Binding}" VerticalAlignment="Center" Margin="4,0"/>
</DataTemplate>
</MenuItem.HeaderTemplate>
</MenuItem>
</HierarchicalDataTemplate>
</Window.Resources>
<Grid>
<Menu ItemsSource="{Binding MenuCategories}"
UsesItemContainerTemplate ="true"
ItemContainerTemplateSelector="{StaticResource MenuItemContainerTemplateSelector}"
/>
</Grid>
Your DataTemplate and HierarchicalDataTemplate describe how the header content of your MenuItem should look like, so nesting another MenuItem there is a bad idea. Instead, keep it really simple and enjoy:
<DataTemplate DataType="{x:Type local:Item}">
<AccessText VerticalAlignment="Center" Text="{Binding Header}" />
</DataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:Category}" ItemsSource="{Binding SubItems}">
<AccessText Text="{Binding Caption}"/>
</HierarchicalDataTemplate>
I got the following XAML-Code:
<ListView x:Name="myList" Height="447" Background="#FFC8F0F1" >
<ListView.ItemTemplate>
<DataTemplate>
<ListViewItem>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding date}" Foreground="{Binding textcolor}" />
<TextBlock Margin="5,0,0,0" Text="{Binding foo}" Foreground="{Binding textcolor}" />
<TextBlock Margin="5,0,0,0" Text="{Binding bar}" Foreground="{Binding textcolor}" />
</StackPanel>
</ListViewItem>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I am starting my program and the code is filling the ListView with ListViewItems, so far so good...
Once I click on the text (Textblocks a.k.a. all the stuff within StackPanel) it won't select/mark the ListViewItem (background-area).
If I click on a free spot where there is no text it's working fine.
I even tried to change ListView to ListBox, it didn't work neither.
Your DataTemplate should not contain a ListViewItem instance, the control creates those containers for you. If you need to set properties on the container use the ListView.ItemContainerStyle.
You might want to bind the ListView's ItemsSource to an ObservableCollection of FooBar objects, then it would be trivial:
FooBarsView:
<UserControl x:Class="ListViewSelectingItem.View.FooBarsView"
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:ListViewSelectingItem.View"
xmlns:vm="clr-namespace:ListViewSelectingItem.ViewModel"
d:DesignHeight="300"
d:DesignWidth="300"
mc:Ignorable="d">
<UserControl.Resources>
<vm:FooBarsViewModel x:Key="fooBarsList"/>
</UserControl.Resources>
<Grid DataContext="{StaticResource fooBarsList}">
<ListView ItemsSource="{Binding FooBars}">
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type vm:FooBar}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Foo}"/>
<TextBlock Text="{Binding Bar}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</UserControl>
FooBarsViewModel:
namespace ListViewSelectingItem.ViewModel
{
using GalaSoft.MvvmLight;
using System.Collections.ObjectModel;
using Model;
public class FooBarsViewModel : ViewModelBase
{
public FooBarsViewModel()
{
FooBars = new ObservableCollection<FooBar>();
FooBars.Add(new FooBar { Foo = "Foo 1", Bar = "Bar 1" });
FooBars.Add(new FooBar { Foo = "Foo 2", Bar = "Bar 2" });
FooBars.Add(new FooBar { Foo = "Foo 3", Bar = "Bar 3" });
}
public ObservableCollection<FooBar> FooBars { get; private set; }
}
}
Im having some problems with databinding inside a DataTemplate. In the ControlTemplate below the textbox in the Grid works and prints out the correct value. But the TextBlock inside the HyperlinkButtons DataTemplate does not work. Though the HyperlinkButtons NavigateUri is bound correctly. Could anyone plz help me with this
I have created a simple example that illustrates my problem.
MainPage.xaml
<UserControl x:Class="SilverlightApplication8.MainPage"
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"
d:DesignHeight="300" d:DesignWidth="400">
<UserControl.Resources>
<ControlTemplate x:Key="EventControlTemplate" TargetType="Button">
<Grid>
<!--WORKS-->
<!--<Grid >
<TextBlock x:Name="TitleTextBlock" Text="{Binding Title}" Foreground="Red" FontWeight="Bold" />
</Grid>-->
<!--DOES NOT WORK-->
<HyperlinkButton TargetName="_blank" NavigateUri="{Binding Url}" >
<HyperlinkButton.ContentTemplate>
<DataTemplate>
<Grid>
<TextBlock Foreground="Green" Text="{Binding Title}"/>
</Grid>
</DataTemplate>
</HyperlinkButton.ContentTemplate>
</HyperlinkButton>
</Grid>
</ControlTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<ItemsControl x:Name="Links" Foreground="White" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border >
<Button Template="{StaticResource EventControlTemplate}" Click="Button_Click"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>
MainPage.xaml.cs
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace SilverlightApplication8
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
List<Events> events = new List<Events>();
events.Add(new Events(){Title = "This is title 1", Url = "http://www.thesun.co.uk"});
events.Add(new Events(){Title = "This is title 2", Url = "http://www.thesun.co.uk"});
events.Add(new Events() { Title = "This is title 3", Url = "http://www.thesun.co.uk" });
Links.ItemsSource = events;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
}
}
public class Events
{
public string Url { get; set; }
public string Title { get; set; }
}
}
You're setting the ContentTemplate, the DataContext of which will be the Content of the HyperlinkButton. Since you haven't set the Content, you're attempting to bind against null.
This should work:
<HyperlinkButton TargetName="_blank" NavigateUri="{Binding Url}" Content="{Binding Title}">
<HyperlinkButton.ContentTemplate>
<DataTemplate>
<Grid>
<TextBlock Foreground="Green" Text="{Binding .}"/>
</Grid>
</DataTemplate>
</HyperlinkButton.ContentTemplate>
</HyperlinkButton>
But then that begs the question as to why you're even setting the ContentTemplate instead of just doing this:
<HyperlinkButton TargetName="_blank" NavigateUri="{Binding Url}" Content="{Binding Title}"/>
I am trying to declaratively bind a ComboBox within a DataGrid CellEditingTemplate using a ViewModel. The ComboBox is not being bound. What am I doing wrong?
XAML:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"
xmlns:data="clr-namespace:SilverlightApplication1"
mc:Ignorable="d"
x:Class="SilverlightApplication1.EmployeeDetail"
Width="640" Height="480">
<UserControl.Resources>
<data:EmployeeDetailsViewModel
x:Key="ViewModel"
d:IsDataSource="True" />
</UserControl.Resources>
<Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource ViewModel}}" Background="White">
<sdk:DataGrid ItemsSource="{Binding Employees,Mode=TwoWay}" AutoGenerateColumns="False" CanUserSortColumns="True" CanUserReorderColumns="True" CanUserResizeColumns="True" GridLinesVisibility="All" Height="317" HorizontalAlignment="Left" Margin="12,136,0,0" Name="EmployeesGrid" VerticalAlignment="Top" Width="605">
<sdk:DataGrid.Columns>
<!-- snipped from brevity -->
<sdk:DataGridTemplateColumn Header="Status">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding EmployeeStatus.Description}" TextWrapping="Wrap"></TextBlock>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Path=EmployeeStatuses}" SelectedItem="{Binding EmployeeStatus, Mode=TwoWay}" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
<TextBlock x:Name="SearchLabel" HorizontalAlignment="Left" Margin="12,95,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="106" Height="34"><Run FontWeight="Bold" Text="Search By Name: "/><Run FontSize="9.333" Text="(Last, First)"/></TextBlock>
<TextBox x:Name="SearchParam" HorizontalAlignment="Left" Margin="144,101,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="162"/>
<Button x:Name="SearchButton" Content="Search" HorizontalAlignment="Right" Margin="0,102,242,0" VerticalAlignment="Top" Width="75" Click="SearchButton_Click"/>
</Grid>
</UserControl>
VIEW MODEL:
using System.Collections.ObjectModel;
using SilverlightApplication1.EmployeeService;
using SilverlightApplication1.ViewModels;
namespace SilverlightApplication1
{
public class EmployeeDetailsViewModel : ViewModelBase
{
readonly IEmployeeServiceAgent _serviceAgent;
ObservableCollection<EmployeeStatus> _employeeStatuses { get; set; }
ObservableCollection<Employee> _employees { get; set; }
public EmployeeDetailsViewModel() : this(new EmployeeServiceAgent()) { }
public EmployeeDetailsViewModel(IEmployeeServiceAgent serviceAgent)
{
if (!IsDesignTime)
{
_serviceAgent = serviceAgent;
GetAllEmployees();
GetEmployeeStatuses();
}
}
public ObservableCollection<Employee> Employees
{
get { return _employees; }
set
{
if(_employees!=value)
{
_employees = value;
OnNotifyPropertyChanged("Employees");
}
}
}
public ObservableCollection<EmployeeStatus> EmployeeStatuses
{
get { return _employeeStatuses; }
set
{
if (_employeeStatuses != value)
{
_employeeStatuses = value;
OnNotifyPropertyChanged("EmployeeStatuses");
}
}
}
private void GetAllEmployees()
{
_serviceAgent.GetAll((s, e) => Employees = e.Result);
}
private void GetEmployeeStatuses()
{
_serviceAgent.GetEmployeeStatuses((s, e) => EmployeeStatuses = e.Result);
}
}
}
Update:
This seems wrong but I figured out how to get the binding working by re-referencing the ViewModel in the ItemSource Binding:
<ComboBox ItemsSource="{Binding Source={StaticResource ViewModel},Path=EmployeeStatuses}"
DisplayMemberPath="Description"
SelectedItem="{Binding EmployeeStatus, Mode=TwoWay}" />
However, a am now experiencing a problem where the SelectedItem is not bound! What am I doing wrong?
The problem is a common one that people run into. When you're in the data template of the column, you're no longer bound the the view model. At that point your data context is the EmployeeStatus object (which doesn't have an EmployeeStatuses property to bind to).
So to get the combobox binding to work you can use the ElementName=LayoutRoot to bind back up the tree to the root ViewModel.
Update: Here would be the full syntax for your binding:
{Binding DataContext.EmployeeStatuses, ElementName=LayoutRoot}
Update2: I've actually run into this as well and there is a workaround you have to implement to get the element name binding to work inside a datagrid.
If Bryant's solution does not work (in SL4), use static resources. See this link: http://blog.digitaltools.com/post/2011/05/06/Binding-a-Datagride28099s-ComboBox.aspx
Or, by creating the static resource in xaml: http://forums.silverlight.net/post/370135.aspx