none
Binding a command from ViewModel to an event within a UserControl RRS feed

  • Question

  • I have MainWindowViewModel and it contains some commands. I also have a UserControl with a slider that is displayed in MainWindow.xaml. When I move the slider within the UserControl, I want a command from MainWindowViewModel to be called.

    What's the best way to do this?

    I feel like there should be a way for me to expose the ValueChanged event from the slider (like a dependency property) and then bind my command to that exposed event.

    Something like this...

    <controls:MyUserControl SliderValueChanged={Binding Path=MyCommand} />

    Thanks!

    Monday, March 4, 2019 4:39 PM

All replies

  • Bind the value property of the slider to a double propfull in your viewmodel.

    Call whatever method you want to run from the setter of the propfull.


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    Monday, March 4, 2019 6:47 PM
    Moderator
  • That would work if the property that I'm binding that value to was in MainWindowViewModel, but that property is in a separate class.

    I'd also just like to know the procedure for binding a command to an exposed event that's in a UserControl.

    Monday, March 4, 2019 7:34 PM
  • You need to point the Binder to the UserControl itself, Since you are in the UserControl tag, just reference 'self', otherwise you can look up the ancestors to get to it if you are calling from within the UserControl. Basically:

    {Binding RelativeSource={RelativeSource Self}, Path=MyCommand}
    
    or if you have a different Property/Object/DataContext
    
    {Binding RelativeSource={RelativeSource Self}, Path=DataContext.MyCommand}

    I think the second one will work for you since the UserControl will inherit from the parent, and you get that handle that way. First way is if you have the Command On the UserControl itself, second way, you can do however you set it up.

    Hope this helps!


    noorbakhsh حميد نوربخش



    • Edited by noorbakhsh Monday, March 4, 2019 8:03 PM
    Monday, March 4, 2019 7:57 PM
  • Hi Andy;
    I solve this problem like this demo:

    Window:

    <Window x:Class="WpfApp1.Window05"
            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:WpfApp1"
            mc:Ignorable="d"
            Title="Window05" Height="450" Width="800">
      <StackPanel>
        <local:Window05UC1 MyCommand="{Binding Cmd}"/>
      </StackPanel>
    </Window>


    using System.Windows;
    using System.Windows.Input;
    
    namespace WpfApp1
    {
      /// <summary>
      /// Interaction logic for Window05.xaml
      /// </summary>
      public partial class Window05 : Window
      {
        public Window05()
        {
          InitializeComponent();
          this.DataContext = this;
        }
    
        public ICommand Cmd { get { return new RelayCommand((state) => MessageBox.Show($"Click from UserControl, State: {state}")); } }
      }
    }
    

    UserControl:

    <UserControl x:Class="WpfApp1.Window05UC1"
                 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:WpfApp1"
                 mc:Ignorable="d" 
                 d:DesignHeight="450" d:DesignWidth="800">
      <StackPanel x:Name="sp">
        <Button Content="Click Event from UserControl" Command="{Binding Cmd}" CommandParameter="Par from UC"/>
      </StackPanel>
    </UserControl>

    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    
    namespace WpfApp1
    {
      /// <summary>
      /// Interaction logic for Window05UC1.xaml
      /// </summary>
      public partial class Window05UC1 : UserControl
      {
        public Window05UC1()
        {
          InitializeComponent();
          this.sp.DataContext = this;
        }
    
        private ICommand extCmd;
    
        public ICommand Cmd { get { return new RelayCommand((state)=>extCmd.Execute(state)); } }
    
          public static readonly DependencyProperty MyCommandProperty =
           DependencyProperty.RegisterAttached("MyCommand",
           typeof(ICommand),
           typeof(Window05UC1),
           new UIPropertyMetadata(null, OnMyCommandChanged));
        public static ICommand GetMyCommand(DependencyObject obj) { return (ICommand)(obj.GetValue(MyCommandProperty)); }
        public static void SetMyCommand(DependencyObject obj, Window02TextBoxBehavior value) { obj.SetValue(MyCommandProperty, value); }
    
        private static void OnMyCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
          Window05UC1 uc = d as Window05UC1;
          if (uc == null) return;
          if (e.NewValue is ICommand) uc.extCmd = e.NewValue as ICommand;
        }
      }
    }
    


    --
    Viele Grüsse / Best Regards
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Monday, March 4, 2019 8:43 PM
  • Hello! I'm not exactly sure what you mean.

    How do I expose a slider value changed event from my UserControl so that a Command in my MainWindowViewModel could be executed?

    I know for my slider I can set it up like this...

    <Slider ValueChanged"MySlider_ValueChanged" />

    But I'm not sure how to expose that ValueChanged event from the UserControl, and then bind a Command to that exposed event from MainWindowViewModel.

    Tuesday, March 12, 2019 4:59 PM
  • Hi,
    see my Demo with Slider in UserControl:

    Window:

    <Window x:Class="WpfApp1.Window09"
            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:WpfApp1"
            mc:Ignorable="d"
            Title="Window09" Height="450" Width="800">
      <StackPanel>
        <local:Window09UC1 MyCommand="{Binding Cmd}"/>
      </StackPanel>
    </Window>

    Window CodeBehind:

    using System.Windows;
    using System.Windows.Input;
    
    namespace WpfApp1
    {
      /// <summary>
      /// Interaction logic for Window05.xaml
      /// </summary>
      public partial class Window09 : Window
      {
        public Window09()
        {
          InitializeComponent();
          this.DataContext = this;
        }
    
        public ICommand Cmd { get { return new RelayCommand((state) => MessageBox.Show($"Event from UserControl, State: {state}")); } }
      }
    }

    XAML UserControl:

    <UserControl x:Class="WpfApp1.Window09UC1"
                 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:WpfApp1"
                 mc:Ignorable="d" 
                 d:DesignHeight="450" d:DesignWidth="800">
      <StackPanel x:Name="sp">
        <Slider ValueChanged="Slider_ValueChanged"/>
      </StackPanel>
    </UserControl>
    

    CodeBehind UserControl:

    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    
    namespace WpfApp1
    {
      /// <summary>
      /// Interaction logic for Window05UC1.xaml
      /// </summary>
      public partial class Window09UC1 : UserControl
      {
        public Window09UC1()
        {
          InitializeComponent();
          this.sp.DataContext = this;
        }
    
        private ICommand extCmd;
    
          public static readonly DependencyProperty MyCommandProperty =
           DependencyProperty.RegisterAttached("MyCommand",
           typeof(ICommand),
           typeof(Window09UC1),
           new UIPropertyMetadata(null, OnMyCommandChanged));
        public static ICommand GetMyCommand(DependencyObject obj) { return (ICommand)(obj.GetValue(MyCommandProperty)); }
        public static void SetMyCommand(DependencyObject obj, Window02TextBoxBehavior value) { obj.SetValue(MyCommandProperty, value); }
    
        private static void OnMyCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
          Window09UC1 uc = d as Window09UC1;
          if (uc == null) return;
          if (e.NewValue is ICommand) uc.extCmd = e.NewValue as ICommand;
        }
    
        private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
          extCmd.Execute(((Slider)sender).Value);
        }
      }
    }


    --
    Viele Grüsse / Best Regards
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Tuesday, March 12, 2019 5:17 PM