ViewModel data will not bind to UserControl exclusively - wpf

I have a simple test ViewModel for my MainWindow:
namespace MyApp.ViewModels
{
class MainWindowViewModel : ViewModelBase
{
public string Test { get; set; } = "TEST";
}
}
Can't get any simpler than that. Now I give my MainWindow knowledge about it and bind the Test property to a TextBox and an own UserControl:
<Window x:Class="MyApp.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:MyApp"
xmlns:uc="clr-namespace:MyApp.UserControls"
xmlns:vm="clr-namespace:MyApp.ViewModels"
mc:Ignorable="d"
Width="800"
Height="600">
<Window.DataContext>
<vm:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox HorizontalAlignment="Left"
Grid.Row="0"
TextWrapping="Wrap"
VerticalAlignment="Top"
Width="120"
Text="{Binding Test, PresentationTraceSources.TraceLevel=High}" />
<uc:TestUserControl Grid.Row="1" Test="{Binding Test, PresentationTraceSources.TraceLevel=High}" />
</Grid>
</Window>
Again, very simple.
My TestUserControl looks like that:
<UserControl x:Class="MyApp.UserControls.TestUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MyApp.UserControls"
mc:Ignorable="d"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBox HorizontalAlignment="Left"
TextWrapping="Wrap"
VerticalAlignment="Top"
Width="120"
Text="{Binding Test, PresentationTraceSources.TraceLevel=High}" />
</Grid>
</UserControl>
namespace MyApp.UserControls
{
public partial class TestUserControl : UserControl
{
public static readonly DependencyProperty TestProperty =
DependencyProperty.Register("Test", typeof(string), typeof(TestUserControl),
new FrameworkPropertyMetadata((string)String.Empty));
public string Test
{
get { return (string)GetValue(TestProperty); }
set { SetValue(TestProperty, value); }
}
public TestUserControl()
{
InitializeComponent();
}
}
}
What I basically end up with are two TextBoxes, one wrapped in my UserControl, the other not.
Both TextBoxes should contain the text "TEST", but only the one that is not embedded in the UserControl does.
When I skip the binding of the ViewModel like so:
<uc:TestUserControl Grid.Row="1" Test="TEST" />
The text shows up in the TextBox, which indicates that the user control is fine.
This is the debug output:
System.Windows.Data Warning: 56 : Created BindingExpression (hash=52579650) for Binding (hash=50581426) BindingExpression:Path=Test; DataItem=null;
System.Windows.Data Warning: 58 : Path: 'Test'
System.Windows.Data Warning: 60 : BindingExpression (hash=52579650): Default mode resolved to TwoWay
System.Windows.Data Warning: 61 : BindingExpression (hash=52579650): Default update trigger resolved to LostFocus
System.Windows.Data Warning: 62 : BindingExpression (hash=52579650): Attach to System.Windows.Controls.TextBox.Text (hash=15537542)
System.Windows.Data Warning: 67 : BindingExpression (hash=52579650): Resolving source
System.Windows.Data Warning: 70 : BindingExpression (hash=52579650): Found data context element: TextBox (hash=15537542) (OK)
System.Windows.Data Warning: 78 : BindingExpression (hash=52579650): Activate with root item MainWindowViewModel (hash=13189358)
System.Windows.Data Warning: 108 : BindingExpression (hash=52579650): At level 0 - for MainWindowViewModel.Test found accessor RuntimePropertyInfo(Test)
System.Windows.Data Warning: 104 : BindingExpression (hash=52579650): Replace item at level 0 with MainWindowViewModel (hash=13189358), using accessor RuntimePropertyInfo(Test)
System.Windows.Data Warning: 101 : BindingExpression (hash=52579650): GetValue at level 0 from MainWindowViewModel (hash=13189358) using RuntimePropertyInfo(Test): 'TEST'
System.Windows.Data Warning: 80 : BindingExpression (hash=52579650): TransferValue - got raw value 'TEST'
System.Windows.Data Warning: 89 : BindingExpression (hash=52579650): TransferValue - using final value 'TEST'
System.Windows.Data Warning: 56 : Created BindingExpression (hash=26543418) for Binding (hash=62601592) BindingExpression:Path=Test; DataItem=null;
System.Windows.Data Warning: 58 : Path: 'Test'
System.Windows.Data Warning: 60 : BindingExpression (hash=26543418): Default mode resolved to TwoWay
System.Windows.Data Warning: 61 : BindingExpression (hash=26543418): Default update trigger resolved to LostFocus
System.Windows.Data Warning: 62 : BindingExpression (hash=26543418): Attach to System.Windows.Controls.TextBox.Text (hash=21868813)
System.Windows.Data Warning: 67 : BindingExpression (hash=26543418): Resolving source
System.Windows.Data Warning: 70 : BindingExpression (hash=26543418): Found data context element: TextBox (hash=21868813) (OK)
System.Windows.Data Warning: 78 : BindingExpression (hash=26543418): Activate with root item TestUserControl (hash=21522166)
System.Windows.Data Warning: 108 : BindingExpression (hash=26543418): At level 0 - for TestUserControl.Test found accessor DependencyProperty(Test)
System.Windows.Data Warning: 104 : BindingExpression (hash=26543418): Replace item at level 0 with TestUserControl (hash=21522166), using accessor DependencyProperty(Test)
System.Windows.Data Warning: 101 : BindingExpression (hash=26543418): GetValue at level 0 from TestUserControl (hash=21522166) using DependencyProperty(Test): ''
System.Windows.Data Warning: 80 : BindingExpression (hash=26543418): TransferValue - got raw value ''
System.Windows.Data Warning: 89 : BindingExpression (hash=26543418): TransferValue - using final value ''
System.Windows.Data Warning: 56 : Created BindingExpression (hash=3865173) for Binding (hash=22799085) BindingExpression:Path=Test; DataItem=null;
System.Windows.Data Warning: 58 : Path: 'Test'
System.Windows.Data Warning: 60 : BindingExpression (hash=3865173): Default mode resolved to OneWay
System.Windows.Data Warning: 61 : BindingExpression (hash=3865173): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 62 : BindingExpression (hash=3865173): Attach to MyApp.UserControls.TestUserControl.Test (hash=21522166)
System.Windows.Data Warning: 67 : BindingExpression (hash=3865173): Resolving source
System.Windows.Data Warning: 70 : BindingExpression (hash=3865173): Found data context element: TestUserControl (hash=21522166) (OK)
System.Windows.Data Warning: 78 : BindingExpression (hash=3865173): Activate with root item TestUserControl (hash=21522166)
System.Windows.Data Warning: 107 : BindingExpression (hash=3865173): At level 0 using cached accessor for TestUserControl.Test: DependencyProperty(Test)
System.Windows.Data Warning: 104 : BindingExpression (hash=3865173): Replace item at level 0 with TestUserControl (hash=21522166), using accessor DependencyProperty(Test)
System.Windows.Data Warning: 101 : BindingExpression (hash=3865173): GetValue at level 0 from TestUserControl (hash=21522166) using DependencyProperty(Test): ''
System.Windows.Data Warning: 80 : BindingExpression (hash=3865173): TransferValue - got raw value ''
System.Windows.Data Warning: 89 : BindingExpression (hash=3865173): TransferValue - using final value ''
What is the reason for this issue and how to fix it, please?

don't change UserControl DataContext - you are breaking the connection with Window DataContext. Instead change Text bidning to refer to Test property via ElementName.
<UserControl x:Class="MyApp.UserControls.TestUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MyApp.UserControls"
mc:Ignorable="d"
Name="userControl"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBox HorizontalAlignment="Left"
TextWrapping="Wrap"
VerticalAlignment="Top"
Width="120"
Text="{Binding Test, ElementName=userControl, PresentationTraceSources.TraceLevel=High}" />
</Grid>
</UserControl>
note that even without ElementName=userControl the binding with work, but it will connect directly to dataContext - to MainWindowViewModel.Test and not TestUserControl.Test property. In that case setting property without binding - <uc:TestUserControl Grid.Row="1" Test="TEST" /> - won't work.
also change TestProperty to two-way property:
public static readonly DependencyProperty TestProperty = DependencyProperty.Register
(
"Test",
typeof(string),
typeof(TestUserControl),
new FrameworkPropertyMetadata(String.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)
);

Related

WPF Datgrid not updating

I am having problems with my WPF Datagrid updating in the UI.
I am trying to use MVVM.
I am using an observable collection:
public ObservableCollection<OCInspections> MyInspectionList
{
get { return _MyInspectionList; }
set { _MyInspectionList = value; OnPropertyChanged("MyInspectionList"); }
}
Which is attached to an IcollectionView:
MyInspectionView = CollectionViewSource.GetDefaultView(MyInspectionList);
with property...
public ICollectionView MyInspectionView
{
get { return _MyInspectionView; }
set { _MyInspectionView = value; OnPropertyChanged("MyInspectionView"); }
}
which is attached to a datagrid items source:
<DataGrid x:Name="InspectionGrid" Style="{StaticResource DataGridStyle}" SelectionUnit="FullRow" ItemsSource="{Binding MyInspectionView, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, diag:PresentationTraceSources.TraceLevel=High}" SelectedValue="{Binding Path=MySelectedInspection,Mode=TwoWay}" >
When I filter the grid, the UI updates:
public string ToggleText
{
get {
return _ToggleText ?? (_ToggleText = "Open Orders"); }
set {
_ToggleText = value;
OnPropertyChanged("ToggleText");
FilterMe();
}
}
private void FilterMe()
{
MyInspectionView.Filter = O =>
{
OCInspections P = O as OCInspections;
if (ToggleState == true)
{
return P.CompleteDate == null;
}
else
{
return P.CompleteDate != null;
}
};
}
However, there are two oddities, which may be related:
If I try to Sort the grid the UI doesn't update.
private void Click_DefaultSort()
{
MyInspectionView.SortDescriptions.Add(new SortDescription("StopReasonID", ListSortDirection.Ascending));
MyInspectionView.SortDescriptions.Add(new SortDescription("StartedDate", ListSortDirection.Ascending));
MyInspectionView.SortDescriptions.Add(new SortDescription("ReceiptDate", ListSortDirection.Ascending));
}
If a user enters data in the new row and I add it to the observable collection, it will add and show in the UI, but it will not automatically add the next new blank row. However, if I click on another row or press enter it will add the new blank row:
before clicking add row button
after clicking the add button
after clicking any existing row or pressing enter:
I think these two items may be related which is why I'm including them in the same question.
this is the closest thing I found for the second problem as an example:
No new row with Datagrid Editing after updating ObservableCollection
EDIT: another observation is that the binding is throwing these warnings, but I have been unsuccessful at resolving:
System.Windows.Data Warning: 56 : Created BindingExpression (hash=5405340) for Binding (hash=39717249)
System.Windows.Data Warning: 58 : Path: 'MyInspectionView'
System.Windows.Data Warning: 62 : BindingExpression (hash=5405340): Attach to System.Windows.Controls.DataGrid.ItemsSource (hash=42463340)
System.Windows.Data Warning: 67 : BindingExpression (hash=5405340): Resolving source
System.Windows.Data Warning: 70 : BindingExpression (hash=5405340): Found data context element: DataGrid (hash=42463340) (OK)
System.Windows.Data Warning: 78 : BindingExpression (hash=5405340): Activate with root item MainWindowViewModel (hash=63685038)
System.Windows.Data Warning: 108 : BindingExpression (hash=5405340): At level 0 - for MainWindowViewModel.MyInspectionView found accessor RuntimePropertyInfo(MyInspectionView)
System.Windows.Data Warning: 104 : BindingExpression (hash=5405340): Replace item at level 0 with MainWindowViewModel (hash=63685038), using accessor RuntimePropertyInfo(MyInspectionView)
System.Windows.Data Warning: 101 : BindingExpression (hash=5405340): GetValue at level 0 from MainWindowViewModel (hash=63685038) using RuntimePropertyInfo(MyInspectionView): ListCollectionView (hash=48179284)
System.Windows.Data Warning: 80 : BindingExpression (hash=5405340): TransferValue - got raw value ListCollectionView (hash=48179284)
System.Windows.Data Warning: 84 : BindingExpression (hash=5405340): TransferValue - implicit converter produced ListCollectionView (hash=48179284)
System.Windows.Data Warning: 89 : BindingExpression (hash=5405340): TransferValue - using final value ListCollectionView (hash=48179284)

ValidationRule and DependencyObject

I need to send Binding values to a ValidationRule. I am using a DependencyObject, but the values are always null.
Here is my DependencyObject
public class MyDependencyObject : DependencyObject
{
public string BindingValue
{
get { return (string)GetValue(BindingValueProperty); }
set { SetValue(BindingValueProperty, value); }
}
public static readonly DependencyProperty BindingValueProperty =
DependencyProperty.Register("BindingValue", typeof(string), typeof(MyDependencyObject), new UIPropertyMetadata(null));
}
Here is my ValidationRule:
public class MyTextBoxValidationRule : ValidationRule
{
private MyDependencyObject _TxtVal;
public MyDependencyObject TxtVal
{
get { return _TxtVal; }
set { _TxtVal = value; }
}
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
//Validation Logic
}
}
Here is the XAML:
<TextBox >
<TextBox.Text>
<Binding Path="DataUserTypes"
NotifyOnValidationError="True"
ValidatesOnDataErrors="True"
Mode="TwoWay"
UpdateSourceTrigger="PropertyChanged"
NotifyOnSourceUpdated="True"
NotifyOnTargetUpdated="True"
Delay="100">
<Binding.ValidationRules>
<local:MyTextBoxValidationRule ValidatesOnTargetUpdated="True" >
<local:MyTextBoxValidationRule.TxtVal >
<local:MyDependencyObject
TxtVal="{Binding Path=ValidateValue}" />
</local:MyTextBoxValidationRule.TxtVal>
</local:MyTextBoxValidationRule>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
When I step through Validate in MyTextBoxValidationRule TxtVal.BindingValue is always null. I have no idea why
edit:
I changed DisplayValue to DataUserTypes as there seems to be some confusion.
<Binding Path="DataUserTypes"
That is the binding for the Text value of the textbox. I need to validate DataUserTypes based on the property ValidateValue. I am trying to do that with the DependencyObject TxtVal.
I also fixed a copy and paste type. There was a field called TextValID that should have been TxtVal. Sorry about that.
<local:MyTextBoxValidationRule ValidatesOnTargetUpdated="True" >
<local:MyTextBoxValidationRule.TxtVal >
<local:MyDependencyObject
BindingValue="{Binding ValidateValue, PresentationTraceSources.TraceLevel=High}"
/>
</local:MyTextBoxValidationRule.TxtVal>
</local:MyTextBoxValidationRule>
PresentationTraceSources.TraceLevel=High produces the following trace output in the VS Output pane:
System.Windows.Data Warning: 56 : Created BindingExpression (hash=24230272) for Binding (hash=28316044)
System.Windows.Data Warning: 58 : Path: 'ValidateValue'
System.Windows.Data Warning: 60 : BindingExpression (hash=24230272): Default mode resolved to OneWay
System.Windows.Data Warning: 61 : BindingExpression (hash=24230272): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 62 : BindingExpression (hash=24230272): Attach to Lines.MyDependencyObject.BindingValue (hash=37689768)
System.Windows.Data Warning: 64 : BindingExpression (hash=24230272): Use Framework mentor <null>
System.Windows.Data Warning: 67 : BindingExpression (hash=24230272): Resolving source
System.Windows.Data Warning: 69 : BindingExpression (hash=24230272): Framework mentor not found
System.Windows.Data Warning: 65 : BindingExpression (hash=24230272): Resolve source deferred
'Lines.exe' (CLR v4.0.30319: Lines.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework.Aero\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.Aero.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
System.Windows.Data Warning: 67 : BindingExpression (hash=24230272): Resolving source
System.Windows.Data Warning: 69 : BindingExpression (hash=24230272): Framework mentor not found
Long story short, that instance of local:MyDependencyObject has no place to inherit a DataContext from, because its parent isn't in the visual tree.
You could use a BindingProxy to work around that, but what are you binding to? ValidateValue must be a property of something; but of what? If it's a property of the parent viewmodel, this will do it:
<TextBox.Resources>
<local:BindingProxy
x:Key="ViewmodelProxy"
Data="{Binding}"
/>
</TextBox.Resources>
<TextBox.Text>
<Binding Path="DataUserTypes"
NotifyOnValidationError="True"
ValidatesOnDataErrors="True"
Mode="TwoWay"
UpdateSourceTrigger="PropertyChanged"
NotifyOnSourceUpdated="True"
NotifyOnTargetUpdated="True"
Delay="100">
<Binding.ValidationRules>
<local:MyTextBoxValidationRule ValidatesOnTargetUpdated="True" >
<local:MyTextBoxValidationRule.TxtVal>
<local:MyDependencyObject
BindingValue="{Binding Data.ValidateValue, Source={StaticResource ViewmodelProxy}}"
/>
</local:MyTextBoxValidationRule.TxtVal>
</local:MyTextBoxValidationRule>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
Binding proxy:
public class BindingProxy : Freezable
{
#region Overrides of Freezable
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
#endregion
public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
// Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}

WPF binding objects to Listbox, text not appearing

I searched and could not find an answer to my problem can someone help? I tried to bind a list of objects to a listbox. I have the correct number of items (I can still select them) but I could not see the texts.
My Xaml Code:
<ListBox x:Name="listbox_leave" BorderThickness="0">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding leaveName}" />
<TextBlock Text="{Binding numberOfDays}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This is backend code:
ObservableCollection<Leave> leavelist = new ObservableCollection<Leave>();
leavelist = DbControl.loadLeaveDetails();
listbox_leave.ItemsSource = leavelist;
and my Leave Class:
class Leave
{
public string leaveName;
public string LeaveName
{
get { return leaveName; }
set { leaveName = value; }
}
public string numberOfDays;
public string NumberOfDays
{
get { return numberOfDays; }
set { numberOfDays = value; }
}
}
When I debug, the ObservableCollection list of Leave has all the correct data, my listbox display blank but it have the correct number of object Leave in it (I could select them) but there is no text displaying. And I have this msg:
System.Windows.Data Error: 40 : BindingExpression path error: 'leaveName' property not found on 'object' ''Leave' (HashCode=44930696)'. BindingExpression:Path=leaveName; DataItem='Leave' (HashCode=44930696); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Error: 40 : BindingExpression path error: 'numberOfDays' property not found on 'object' ''Leave' (HashCode=44930696)'. BindingExpression:Path=numberOfDays; DataItem='Leave' (HashCode=44930696); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Error: 40 : BindingExpression path error: 'leaveName' property not found on 'object' ''Leave' (HashCode=29274103)'. BindingExpression:Path=leaveName; DataItem='Leave' (HashCode=29274103); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Error: 40 : BindingExpression path error: 'numberOfDays' property not found on 'object' ''Leave' (HashCode=29274103)'. BindingExpression:Path=numberOfDays; DataItem='Leave' (HashCode=29274103); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
Can Someone help??
You are trying to bind to the fields (leaveName and numberOfDays) instead of the properties (LeaveName and NumberOfDays), and this is not supported in WPF.
Change it to:
<ListBox x:Name="listbox_leave" BorderThickness="0">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding LeaveName}" />
<TextBlock Text="{Binding NumberOfDays}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Also, you should probably go ahead and make the fields private (leaveName and numberOfDays) instead of public.

Prism command binding not executing

in my project i used wpf + prism.Inside a view,i must invoke a command inside a context menu, the command is defined into the viewmodel class.this is the view:
<UserControl x:Class="GrigoLync.Modules.LyncClient.Contatti.ContattiView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:infr="clr-namespace:GrigoLync.infrastructure.Model.Lync;assembly=GrigoLync.infrastructure"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Label Grid.Column="0" Grid.Row="0" FontSize="12" Margin="5">Contatti</Label>
<TreeView x:Name="groupTreeView" Margin="10" ItemsSource="{Binding GruppiLync}" >
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=ContattiLync}">
<TextBlock Text="{Binding Path=Nome}" />
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Uri}" Tag="{Binding}">
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header ="Invia messaggio istantaneo"
Command="{Binding PlacementTarget.Tag.SendInstantMessageCommand,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}, diag:PresentationTraceSources.TraceLevel=High}"/>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
the following is the viewmodel class:
[Export(typeof(ContattiViewModel))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class ContattiViewModel : NotificationObject
{
private readonly ILyncClientService lyncClientService;
private readonly IRegionManager regionManager;
private readonly IEventAggregator eventAggregator;
private List<GruppoLync> gruppiLync;
private ICommand sendInstantMessageCommand;
[ImportingConstructor]
public ContattiViewModel(ILyncClientService lyncClientService, IRegionManager regionManager, IEventAggregator eventAggregator)
{
if (lyncClientService == null)
{
throw new ArgumentNullException("lyncClientService");
}
if (regionManager == null)
{
throw new ArgumentNullException("regionManager");
}
if (eventAggregator == null)
{
throw new ArgumentNullException("eventAggregator");
}
this.lyncClientService = lyncClientService;
this.regionManager = regionManager;
this.eventAggregator = eventAggregator;
this.gruppiLync = lyncClientService.elencoGruppiLync();
this.sendInstantMessageCommand = new DelegateCommand<object>(this.SendInstantMessage);
//groupTreeView.DataItems = this.gruppiLync;
}
public ICommand SendInstantMessageCommand { get { return this.sendInstantMessageCommand; } }
public List<GruppoLync> GruppiLync
{
get
{
return this.gruppiLync;
}
}
private void SendInstantMessage(object aContattoLync)
{
//This point is not executed!
}
}
}
When i select from the user interface the menu item "Invia Messaggio istantaneo" the command is not invoke, This point is not executed
can help me please?!!!!
this is the GruppoLync class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;
namespace GrigoLync.infrastructure.Model.Lync
{
public class GruppoLync : INotifyPropertyChanged
{
private string nome;
public string Nome
{
get { return nome; }
set { nome = value;
OnPropertyChanged(new PropertyChangedEventArgs("Nome"));
}
}
private ObservableCollection<ContattoLync> contattiLync;
public ObservableCollection<ContattoLync> ContattiLync
{
get { return contattiLync; }
set
{
contattiLync = value;
OnPropertyChanged(new PropertyChangedEventArgs("ContattiLync"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
public GruppoLync(string nome, ObservableCollection<ContattoLync> contattiLync)
{
Nome = nome;
ContattiLync = contattiLync;
}
}
}
and this is ContattoLync class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using Microsoft.Practices.Prism.Commands;
namespace GrigoLync.infrastructure.Model.Lync
{
public class ContattoLync
{
public string Uri { get; set; }
public string Stato { get; set; }
}
}
I report also the trace log of the binding:
System.Windows.Data Warning: 54 : Created BindingExpression (hash=37997052) for Binding (hash=17879784)
System.Windows.Data Warning: 56 : Path: 'PlacementTarget.Tag.SendInstantMessageCommand'
System.Windows.Data Warning: 58 : BindingExpression (hash=37997052): Default mode resolved to OneWay
System.Windows.Data Warning: 59 : BindingExpression (hash=37997052): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 60 : BindingExpression (hash=37997052): Attach to System.Windows.Controls.MenuItem.Command (hash=47163810)
System.Windows.Data Warning: 64 : BindingExpression (hash=37997052): RelativeSource (FindAncestor) requires tree context
System.Windows.Data Warning: 63 : BindingExpression (hash=37997052): Resolve source deferred
System.Windows.Data Warning: 54 : Created BindingExpression (hash=18607377) for Binding (hash=17879784)
System.Windows.Data Warning: 56 : Path: 'PlacementTarget.Tag.SendInstantMessageCommand'
System.Windows.Data Warning: 58 : BindingExpression (hash=18607377): Default mode resolved to OneWay
System.Windows.Data Warning: 59 : BindingExpression (hash=18607377): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 60 : BindingExpression (hash=18607377): Attach to System.Windows.Controls.MenuItem.Command (hash=32025604)
System.Windows.Data Warning: 64 : BindingExpression (hash=18607377): RelativeSource (FindAncestor) requires tree context
System.Windows.Data Warning: 63 : BindingExpression (hash=18607377): Resolve source deferred
System.Windows.Data Warning: 65 : BindingExpression (hash=37997052): Resolving source
System.Windows.Data Warning: 68 : BindingExpression (hash=37997052): Found data context element: <null> (OK)
System.Windows.Data Warning: 71 : Lookup ancestor of type ContextMenu: queried ContextMenu (hash=46231978)
System.Windows.Data Warning: 70 : RelativeSource.FindAncestor found ContextMenu (hash=46231978)
System.Windows.Data Warning: 76 : BindingExpression (hash=37997052): Activate with root item ContextMenu (hash=46231978)
System.Windows.Data Warning: 106 : BindingExpression (hash=37997052): At level 0 - for ContextMenu.PlacementTarget found accessor DependencyProperty(PlacementTarget)
System.Windows.Data Warning: 102 : BindingExpression (hash=37997052): Replace item at level 0 with ContextMenu (hash=46231978), using accessor DependencyProperty(PlacementTarget)
System.Windows.Data Warning: 99 : BindingExpression (hash=37997052): GetValue at level 0 from ContextMenu (hash=46231978) using DependencyProperty(PlacementTarget): <null>
System.Windows.Data Warning: 104 : BindingExpression (hash=37997052): Item at level 1 is null - no accessor
System.Windows.Data Warning: 101 : BindingExpression (hash=37997052): Replace item at level 2 with {NullDataItem}
System.Windows.Data Warning: 78 : BindingExpression (hash=37997052): TransferValue - got raw value {DependencyProperty.UnsetValue}
System.Windows.Data Warning: 86 : BindingExpression (hash=37997052): TransferValue - using fallback/default value <null>
System.Windows.Data Warning: 87 : BindingExpression (hash=37997052): TransferValue - using final value <null>
System.Windows.Data Warning: 65 : BindingExpression (hash=18607377): Resolving source
System.Windows.Data Warning: 68 : BindingExpression (hash=18607377): Found data context element: <null> (OK)
System.Windows.Data Warning: 71 : Lookup ancestor of type ContextMenu: queried ContextMenu (hash=64235)
System.Windows.Data Warning: 70 : RelativeSource.FindAncestor found ContextMenu (hash=64235)
System.Windows.Data Warning: 76 : BindingExpression (hash=18607377): Activate with root item ContextMenu (hash=64235)
System.Windows.Data Warning: 105 : BindingExpression (hash=18607377): At level 0 using cached accessor for ContextMenu.PlacementTarget: DependencyProperty(PlacementTarget)
System.Windows.Data Warning: 102 : BindingExpression (hash=18607377): Replace item at level 0 with ContextMenu (hash=64235), using accessor DependencyProperty(PlacementTarget)
System.Windows.Data Warning: 99 : BindingExpression (hash=18607377): GetValue at level 0 from ContextMenu (hash=64235) using DependencyProperty(PlacementTarget): <null>
System.Windows.Data Warning: 104 : BindingExpression (hash=18607377): Item at level 1 is null - no accessor
System.Windows.Data Warning: 101 : BindingExpression (hash=18607377): Replace item at level 2 with {NullDataItem}
System.Windows.Data Warning: 78 : BindingExpression (hash=18607377): TransferValue - got raw value {DependencyProperty.UnsetValue}
System.Windows.Data Warning: 86 : BindingExpression (hash=18607377): TransferValue - using fallback/default value <null>
System.Windows.Data Warning: 87 : BindingExpression (hash=18607377): TransferValue - using final value <null>
That's because ContextMenus are on a separate logical tree.
This means they don't "inherit" the DataContext of the element they act upon.
A workaround is this:
<TextBlock Tag="{Binding}"> <!-- You may have to use RelativeSource on this Binding, depending on which DataContext you're trying to reach -->
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header="Name of the item"
Command="{Binding PlacementTarget.Tag.MyCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}" />
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
This goes fetching MyCommand on the Tag of the PlacementTarget, in the ContextMenu of this MenuItem.
The PlacementTarget poiting to the TextBlock, and its Tag pointing to the DataContext of your view.
I solve the problem!!!!
<TreeView x:Name="groupTreeView" Margin="10" ItemsSource="{Binding GruppiLync}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=ContattiLync}">
<TextBlock Text="{Binding Path=Nome}" />
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Uri}"
Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType=TreeView}}">
<TextBlock.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header ="Invia messaggio istantaneo"
Command="{Binding SendInstantMessageCommand, diag:PresentationTraceSources.TraceLevel=High}"
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}"/>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
Thanks to All!!!
I think to use binding with "RelativeSource={RelativeSource FindAncestor..." is a little strange, you'd rather bind directly to a property of the item set as the datacontext of your hierchical datatemplate.
check the datacontext of the menuitem to see if its the correct one

UserControl ItemsControl Binding

I am developing a UserControl which contains an ItemsControl of TextBoxes. I have a caption class which is used to control the location/Text of the TextBlock
In the Window XAML
<local:UserControl1>
<local:UserControl1.Captions>
<local:Caption Foreground="Black" Size="10" Text="{Binding Path=SomeText}" X="100" Y ="100"></local:Caption>
</local:UserControl1.Captions>
</local:UserControl1>
The ItemsControl is a canvas with the dataTemplate being a TextBox
<ItemsControl ItemsSource="{Binding Path=Captions}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="Beige" Width="{Binding Path=Width}" Height="{Binding Path=Height}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Text}" Foreground="{Binding Path=Foreground}" FontSize="{Binding Path=Size}" ></TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Top" Value="{Binding Path=Y,PresentationTraceSources.TraceLevel=High}" />
<Setter Property="Canvas.Left" Value="{Binding Path=X,PresentationTraceSources.TraceLevel=High}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
In the UserControl is an ObservableCollection of "Caption" which is derived from Framework element
public class Caption :FrameworkElement
{
/// <summary>
/// The actual text to display
/// </summary>
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
/// <summary>
/// The font size
/// </summary>
public int Size
{
get { return (int)GetValue(SizeProperty); }
set { SetValue(SizeProperty, value); }
}
/// <summary>
/// The text foreground color
/// </summary>
public Brush Foreground
{
get { return (Brush)GetValue(ForegroundProperty); }
set { SetValue(ForegroundProperty, value); }
}
/// <summary>
/// The Top location of the text
/// </summary>
public double Y
{
get { return (double)GetValue(YProperty); }
set { SetValue(YProperty, value); }
}
/// <summary>
/// The left location of the text
/// </summary>
public double X
{
get { return (double)GetValue(XProperty); }
set { SetValue(XProperty, value); }
}
public override string ToString()
{
return string.Format("Caption:{0}//{1}.{2}", this.X, this.Y, this.Text);
}
private static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string),
typeof(Caption),
new PropertyMetadata(
OnPropertyChanged));
private static readonly DependencyProperty SizeProperty = DependencyProperty.Register("Size", typeof(int),
typeof(Caption),
new PropertyMetadata(
OnPropertyChanged));
private static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register("Foreground",
typeof(Brush),
typeof(Caption),
new PropertyMetadata
(OnPropertyChanged));
private static readonly DependencyProperty YProperty = DependencyProperty.Register("Y", typeof(double),
typeof(Caption),
new PropertyMetadata(
OnPropertyChanged));
private static readonly DependencyProperty XProperty = DependencyProperty.Register("X", typeof(double),
typeof(Caption),
new PropertyMetadata(
OnPropertyChanged));
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var caption = (Caption)d;
}
}
Each time a Caption is added to the collection it is added to the logical tree
void Captions_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if(e.Action == NotifyCollectionChangedAction.Add)
{
foreach(Caption c in e.NewItems)
{
AddLogicalChild(c);
c.DataContext = this.DataContext;
}
}
}
The problem is that the binding for the Canvas.Top and Canvas.Left are not working
The debug produces the following
System.Windows.Data Warning: 54 : Created BindingExpression
(hash=14626603) for Binding (hash=8360729)
System.Windows.Data Warning: 56 : Path: 'X'
System.Windows.Data Warning: 58 : BindingExpression (hash=14626603):
Default mode resolved to OneWay
System.Windows.Data Warning: 59 : BindingExpression (hash=14626603):
Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 60 : BindingExpression (hash=14626603):
Attach to WpfApplicationQuery.Caption.Left (hash=33822626)
System.Windows.Data Warning: 65 : BindingExpression (hash=14626603):
Resolving source
System.Windows.Data Warning: 68 : BindingExpression (hash=14626603):
Found data context element: Caption (hash=33822626) (OK)
System.Windows.Data Warning: 76 : BindingExpression (hash=14626603):
Activate with root item
System.Windows.Data Warning: 104 : BindingExpression (hash=14626603):
Item at level 0 is null - no accessor
System.Windows.Data Warning: 78 : BindingExpression (hash=14626603):
TransferValue - got raw value {DependencyProperty.UnsetValue}
System.Windows.Data Warning: 86 : BindingExpression (hash=14626603):
TransferValue - using fallback/default value 'NaN'
System.Windows.Data Warning: 87 : BindingExpression (hash=14626603):
TransferValue - using final value 'NaN'
System.Windows.Data Error: 26 : ItemTemplate and ItemTemplateSelector
are ignored for items already of the ItemsControl's container type;
Type='Caption'
So it seems to binding incorrectly, and I don't know what the last error means
Also, previously, I had Caption derived from DependencyObject, and everything worked (.i.e things got displayed), except Databinding. Hence the switch to framworkElement, as described somewhere on stackoverflow ( and a blog post which I now can't find)
Edit 2012-02-14
Changed the first XAML sample code
Edit 2012-02-14
Caption derives from FrameworkElement so that it can participate in databinding as described here
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/aff23943-5483-40b2-816b-4ce687bc6bf8/
and here
http://kentb.blogspot.com/2008_10_01_archive.html
If Caption implements INotifyPropertyChanged
<local:UserControl1>
<local:UserControl1.Captions>
<local:Caption Foreground="Black" Size="10" Text="Hello" X="100" Y ="100"></local:Caption>
<local:Caption Foreground="Black" Size="10" Text="{Binding Path=Title}" X="100" Y ="100"></local:Caption>
</local:UserControl1.Captions>
</local:UserControl1>
The first line works. The second does'nt, this error is traced.
Cannot find governing FrameworkElement or FrameworkContentElement for target element
However, if Caption is derived from FrameworkElement, it now provides it's own ItemTemplate
So the binding error relating to ItemTemplate/ Selector is produced.

Resources