简体   繁体   中英

Set Property in Viewmodel from Code Behind

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>

Example: 树视图

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!

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);
            }
        }

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM