Reputation: 1828
I think I am overthinking this at this point, but I have a unique situation.
Using a treeviewI am displaying a table and the fields in that table:
XAML:
<TreeView x:Name="myTreeView" PreviewMouseDoubleClick="myTreeView_MouseLeftButtonDown" SelectedValuePath="Name" ItemsSource="{Binding Fields}" ItemContainerStyle="{StaticResource TreeViewItemExpandedStyle}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Fields}">
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="Black" Text="{Binding Table}" />
</StackPanel>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button BorderBrush="Transparent"
Background="White"
Command="">
<StackPanel>
<Path Margin="5"
Data="M0,5 H10 M5,5 V10Z"
Stroke="#2283B4"
StrokeThickness="1"
Height="10"
Width="10" />
</StackPanel>
</Button>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
<TextBlock Height="0" Width="0" Visibility="Collapsed" Text="{Binding Table}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
<!--<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding IsExpanded}" Value="True">
<Setter TargetName="treeIcon"
Property="Data"
Value="M0,5 H10"/>
</DataTrigger>
</HierarchicalDataTemplate.Triggers>-->
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
These treeviews are also their own user controls. The issue I am having is I need to be able to use the selected treeview item in another viewmodel. I also have found no other way to grab the selected treeview item and parent except through the code behind. Below is my entire code behind section for this control.
SourceRowUserControl.xaml.cs:
using Alliance.FromAnywhereControl.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Alliance.FromAnywhereControl.ViewModels;
using System.Reflection;
namespace Alliance.FromAnywhereControl
{
/// <summary>
/// Interaction logic for SourceRowUserControl.xaml
/// </summary>
public partial class SourceRowUserControl : UserControl
{
public SourceRowUserControl()
{
InitializeComponent();
}
private ObservableCollection<ConversionRowUserControl> ConversionTypes = new ObservableCollection<ConversionRowUserControl>();
public ObservableCollection<TableInformation> Fields
{
get { return (ObservableCollection<TableInformation>)GetValue(FieldsProperty); }
set { SetValue(FieldsProperty, value); }
}
// Using a DependencyProperty as the backing store for Fields. This enables animation, styling, binding, etc...
public static readonly DependencyProperty FieldsProperty =
DependencyProperty.Register("Fields", typeof(ObservableCollection<TableInformation>), typeof(SourceRowUserControl), new PropertyMetadata(TableInformation.GetAll(null, null, null, null)));
public String FileTypeImage
{
get { return (String)GetValue(FileTypeImageProperty); }
set { SetValue(FileTypeImageProperty, value); }
}
// Using a DependencyProperty as the backing store for FieldTypeImage. This enables animation, styling, binding, etc...
public static readonly DependencyProperty FileTypeImageProperty =
DependencyProperty.Register("FileTypeImage", typeof(String), typeof(SourceRowUserControl), new PropertyMetadata("File Type Image"));
public SolidColorBrush SpacerColor
{
get { return (SolidColorBrush)GetValue(SpacerColorProperty); }
set { SetValue(SpacerColorProperty, value); }
}
// Using a DependencyProperty as the backing store for SpacerColor. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SpacerColorProperty =
DependencyProperty.Register("SpacerColor", typeof(SolidColorBrush), typeof(SourceRowUserControl), new PropertyMetadata(new SolidColorBrush(Colors.Red)));
public String MiddleLabel
{
get { return (String)GetValue(MiddleLabelProperty); }
set { SetValue(MiddleLabelProperty, value); }
}
// Using a DependencyProperty as the backing store for MiddleLabel. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MiddleLabelProperty =
DependencyProperty.Register("MiddleLabel", typeof(String), typeof(SourceRowUserControl), new PropertyMetadata("Middle Label"));
private void myTreeView_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
try
{
Field selectedField = new Field();
selectedField = (Field)myTreeView.SelectedItem;
ConversionViewModel cvm = new ConversionViewModel();
cvm.AddConversionType(selectedField.Table, selectedField.Name);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
The myTreeViewLeftButtonDown event is where is I am grabbing the selected field and table. As you see, I am then calling a method in another viewmodel, but this will not work how I want it to since it creates a new instance. I just put that there to basically show what I was wanting to do. Overview, I need to be able to use a field in my code behind in a viewmodel that is not connected to the view.
Please let me know if you need anymore information or would like to see more code. Thanks in advance!
Upvotes: 1
Views: 2942
Reputation: 54
Looking at your code, instead of defining new ConversionViewModel(), grab the instance of the ConversionViewModel and then set property on it.
public class ConversionViewModel()
{
private static ConversionViewModel _this;
public ConversionViewModel()
{
InitializeComponent();
_this = this;
}
public static ConversionViewModel GetInstance()
{
return _this;
}
//Other prop and methods
}
private void myTreeView_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
try
{
Field selectedField = new Field();
selectedField = (Field)myTreeView.SelectedItem;
ConversionViewModel.GetInstance().AddConversionType(selectedField.Table, selectedField.Name);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Upvotes: 1
Reputation: 9713
You can give your ItemTemplate
an InputBinding
to the Left Button Click action.
<DataTemplate>
<StackPanel Orientation="Horizontal">
<StackPanel.InputBindings>
<MouseBinding MouseAction="LeftClick"
Command="{Binding DataContext.SomeViewModelCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=TreeView}}"
CommandParameter="{Binding}"/>
</StackPanel.InputBindings>
...
</StackPanel>
</DataTemplate>
To help explain this, the MouseBinding
specifies what command to execute when the LeftClick
occurs on the StackPanel
.
The Command
is bound to the DataContext.SomeViewModelCommand
from your TreeView
.
The CommandParameter
is the Field
bound to the DataTemplate
.
Now, all you need to do is declare a Command in your View Model (SomeViewModelCommand
) where the Command Parameter will be your Field
.
Upvotes: 0