I have a MainWindow.xaml, MainwindowViewModel.cs, HaemogramReport.xaml and HaemogramReport.xaml.cs. I have other files as well in my project, but the problem lies in the above mentioned four files. I am posting the minimal code here so that others can catch the problem.
Now in HaemogramReport.xaml I declare some controls like Grid
, TextBox
, TextBlock
, Rectangle
, Border
, ContentControl
etc.
For example HaemogramReport.xaml
looks like:
<Page.DataContext>
<vm:MainWindowViewModel />
</Page.DataContext>
<Grid DataContext="{Binding Source={StaticResource Settings}}" PreviewMouseDown="Object_Selection" x:Name="Root">
<Border Style="{StaticResource BorderStyle}" x:Name="HaemogramTestBorder"
Grid.Row="{Binding Default.HaemogramTestGridRow}" Grid.Column="{Binding Default.HaemogramTestGridColumn}"
Grid.RowSpan="{Binding Default.HaemogramTestGridRowSpan}" Grid.ColumnSpan="{Binding Default.HaemogramTestGridColumnSpan}">
<Grid>
<Rectangle Fill="Transparent" x:Name="HaemogramTestRectangle"/>
<TextBlock x:Name="HaemogramTestTextBlock"
Text="{Binding Default.HaemogramTestText}" Visibility="{Binding Default.HaemogramTestVisibility}"
Background="{Binding Default.HaemogramTestBackground, Converter={StaticResource colorToSolidColorBrushConverter}}"
Foreground="{Binding Default.HaemogramTestForeground, Converter={StaticResource colorToSolidColorBrushConverter}}"
FontFamily="{Binding Default.HaemogramTestFontFamily, Converter={StaticResource stringToFontFamilyConverter}}"
FontSize="{Binding Default.HaemogramTestFontSize}"
FontWeight="{Binding Default.HaemogramTestFontWeight}" FontStyle="{Binding Default.HaemogramTestFontStyle}"
HorizontalAlignment="{Binding Default.HaemogramTestHorizontalAlignment}"
VerticalAlignment="{Binding Default.HaemogramTestVerticalAlignment}"
Margin="{Binding Default.HaemogramTestMargin}" />
</Grid>
</Border>
</Grid>
When I click on any of the element in the above declared elements, the mousedown event of the grid named Root
is raised.
That event handler is in HaemogramReport.xmal.cs
. Here it is:
private void Object_Selection(object sender, MouseButtonEventArgs e)
{
var mouseWasDownOn = e.Source as FrameworkElement;
if (mouseWasDownOn != null)
{
foreach (Border border in FindVisualChildren<Border>(Root))
{
border.BorderBrush = Brushes.Transparent;
}
if (!(mouseWasDownOn is Border))
{
FindParent<Border>(mouseWasDownOn).BorderBrush = Brushes.Orange;
}
MainWindowViewModel mwvm = new MainWindowViewModel();
mwvm.SelectedObj = mouseWasDownOn;
}
}
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
public static T FindParent<T>(DependencyObject child) where T : DependencyObject
{
//get parent item
DependencyObject parentObject = VisualTreeHelper.GetParent(child);
//we've reached the end of the tree
if (parentObject == null) return null;
//check if the parent matches the type we're looking for
T parent = parentObject as T;
if (parent != null)
return parent;
else
return FindParent<T>(parentObject);
}
In mouseDown handler of Grid named Root
, I say mwvm.SelectedObj = mouseWasDownOn;
SelectedObj is a property of type FrameworkElement which is declared in MainwindowViewModel.cs
as follows:
private FrameworkElement selectedObj;
public FrameworkElement SelectedObj
{
get
{
return selectedObj;
}
set
{
selectedObj = value;
OnPropertyChanged("SelectedObj");
}
}
Now in my MainWindow I have for example a grid and a textBox inside it. The problematic bindings are declared here. xaml looks like:
<Window.DataContext>
<vm:MainWindowViewModel />
</Window.DataContext>
<Grid DataContext="{Binding SelectedObj, UpdateSourceTrigger=PropertyChanged}">
<TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged, TargetNullValue='null', FallbackValue='Error'}"/>
</Grid>
When using the above code, I always get the Text Error
in above TextBox.
At the first chance I thought that this might be the binding error, so I changed my MainWindowViewModel.cs
as follows:
public class MainWindowViewModel : INotifyPropertyChanged
{
public MainWindowViewModel()
{
SelectedObj = txt;
}
TextBlock txt = new TextBlock()
{
Text = "123"
};
private FrameworkElement selectedObj;
public FrameworkElement SelectedObj
{
get
{
return selectedObj;
}
set
{
selectedObj = value;
OnPropertyChanged("SelectedObj");
}
}
}
After making the above changes when I run my project I can see 123
in textbox but when I click on any element the text in the textbox does not change.
Now the question here is that if its a binding error then why in second example I get 123
in textbox while in 1st example I get Error
- the fallback value.
And if it's not a binding error then what is the problem in above code?
Update
When I debug, I found that get
part of SelectedObj
is never called. But I don't know why?
Update -- Reed Copsey
Here is my new class:
public class DesignMethods
{
public static void FindCurrentlyClickedElement(DependencyObject Root, MouseButtonEventArgs e, MainWindowViewModel vm)
{
var mouseWasDownOn = e.OriginalSource as FrameworkElement;
if (mouseWasDownOn != null)
{
foreach (Border border in FindVisualChildren<Border>(Root))
{
border.BorderBrush = Brushes.Transparent;
}
if (!(mouseWasDownOn is Border))
{
FindParent<Border>(mouseWasDownOn).BorderBrush = Brushes.Orange;
}
vm.SelectedObj = mouseWasDownOn;
}
}
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
public static T FindParent<T>(DependencyObject child) where T : DependencyObject
{
//get parent item
DependencyObject parentObject = VisualTreeHelper.GetParent(child);
//we've reached the end of the tree
if (parentObject == null) return null;
//check if the parent matches the type we're looking for
T parent = parentObject as T;
if (parent != null)
return parent;
else
return FindParent<T>(parentObject);
}
}
And I use it like:
private void Object_Selection(object sender, MouseButtonEventArgs e)
{
DesignMethods.FindCurrentlyClickedElement(Root, e, this.DataContext as MainWindowViewModel);
}