If using Resource Dictionary, is it possible for WPF pages to share XAML snippet with events?

jennyliu835 221 Reputation points
2020-08-30T23:26:59.423+00:00

Hi Peter + Daisy,
My question is described in the title.
Here is my initial coding.
Thanks

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,785 questions
0 comments No comments
{count} votes

Accepted answer
  1. Peter Fleischer (former MVP) 19,326 Reputation points
    2020-09-05T03:25:45.413+00:00

    Hi Jenny,
    another approach is to use separate ViewModel for each page inherited from the same base class which corrosponded to the XamlWithControls.xaml.

    Pages_ViewModel_base.cs in pages folder:

    using System;
    using System.ComponentModel;
    using System.IO;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Markup;
    using System.Windows.Media;
    
    namespace WpfApp1.pages
    {
      abstract class  Pages_ViewModel_Base : ICommand, INotifyPropertyChanged
      {
        public ContentControl LoadedXaml
        { get => (ContentControl)XamlReader.Load(new FileStream("pages/XamlWithControls.xaml", FileMode.Open)); }
    
        public Brush TbCommonForeGround { get; set; } = Brushes.Black;
        public string TbCommonText { get; set; }
        public Visibility TbExplainVisibility { get; set; } = Visibility.Hidden;
    
        public void Execute(object parameter)
        {
          switch (parameter.ToString())
          {
            case "Preference":
              TbCommonForeGround = new SolidColorBrush(Colors.Blue);
              OnPropertyChanged(nameof(TbCommonForeGround));
              break;
            case "ExplainOn":
              TbExplainVisibility = Visibility.Visible;
              OnPropertyChanged(nameof(TbExplainVisibility));
              break;
            case "ExplainOff":
              TbExplainVisibility = Visibility.Hidden;
              OnPropertyChanged(nameof(TbExplainVisibility));
              break;
            default:
              break;
          }
        }
    
        public event EventHandler CanExecuteChanged;
        public bool CanExecute(object parameter) => true;
    
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName = "") =>
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
      }
    }
    

    Page1_ViewModel.cs in in pages folder:

    namespace WpfApp1.pages
    {
      class Page1_ViewModel : Pages_ViewModel_Base
      {
        protected Page1_ViewModel() { }
    
        private static Page1_ViewModel _instance;
        public static Page1_ViewModel Instance
        {
          get
          {
            if (_instance == null)
            {
              _instance = new Page1_ViewModel();
              _instance.TbCommonText = "Introduction to Markup Languages on Page 1";
            }
            return _instance;
          }
        }
    
        // additional properties
      }
    }
    

    And in CodeBehind of each page you can instantiate different ViewModels with the same base class:

    using System.Windows.Controls;
    
    namespace WpfApp1.pages
    {
      /// <summary>
      /// Interaction logic for Page1.xaml
      /// </summary>
      public partial class Page1 : Page
      {
        public Page1()
        {
          InitializeComponent();
          this.DataContext = Page1_ViewModel.Instance;
        }
      }
    }
    

    and so on:

    namespace WpfApp1.pages
    {
      class Page2_ViewModel : Pages_ViewModel_Base
      {
        protected Page2_ViewModel() { }
    
        private static Page2_ViewModel _instance;
        public static Page2_ViewModel Instance
        {
          get
          {
            if (_instance == null)
            {
              _instance = new Page2_ViewModel();
              _instance.TbCommonText = "Introduction to Markup Languages on Page 2";
            }
            return _instance;
          }
        }
    
        // additional properties
      }
    }
    

    CodeBehind:

    using System.Windows.Controls;
    
    namespace WpfApp1.pages
    {
      /// <summary>
      /// Interaction logic for Page2.xaml
      /// </summary>
      public partial class Page2 : Page
      {
        public Page2()
        {
          InitializeComponent();
          this.DataContext = Page2_ViewModel.Instance;
        }
      }
    }
    
    1 person found this answer helpful.

3 additional answers

Sort by: Most helpful
  1. Peter Fleischer (former MVP) 19,326 Reputation points
    2020-08-31T05:40:13.837+00:00

    Hi Jenny,
    I changed your demo and uploaded here.

    In new demo I use Interactivity.dll (from Nuget) for Binding Commands and Events in DataTemplate. Properties in DataTemplate are bound to ViewModel instance (WpfApp1.pages.general_pages.Pages_ViewModel).

    21487-x.gif

    1 person found this answer helpful.

  2. Peter Fleischer (former MVP) 19,326 Reputation points
    2020-09-05T03:00:34.613+00:00

    Hi Jenny,
    if you want to use for each page different ViewModel instance from the same type you can try this in your demo:

    Pages_ViewModel.cs in pages folder:

    using System;
    using System.ComponentModel;
    using System.IO;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Markup;
    using System.Windows.Media;
    
    namespace WpfApp1.pages
    {
      class Pages_ViewModel : ICommand, INotifyPropertyChanged
      {
        public ContentControl LoadedXaml
        { get => (ContentControl)XamlReader.Load(new FileStream("pages/XamlWithControls.xaml", FileMode.Open)); }
    
        public Brush TbCommonForeGround { get; set; } = Brushes.Black;
        public string TbCommonText { get; set; }
        public Visibility TbExplainVisibility { get; set; } = Visibility.Hidden;
    
        public void Execute(object parameter)
        {
          switch (parameter.ToString())
          {
            case "Preference":
              TbCommonForeGround = new SolidColorBrush(Colors.Blue);
              OnPropertyChanged(nameof(TbCommonForeGround));
              break;
            case "ExplainOn":
              TbExplainVisibility = Visibility.Visible;
              OnPropertyChanged(nameof(TbExplainVisibility));
              break;
            case "ExplainOff":
              TbExplainVisibility = Visibility.Hidden;
              OnPropertyChanged(nameof(TbExplainVisibility));
              break;
            default:
              break;
          }
        }
    
        public event EventHandler CanExecuteChanged;
        public bool CanExecute(object parameter) => true;
    
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName = "") =>
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
      }
    }
    

    And in CodeBehind of each page you can instantiate this class:

    using System.Windows.Controls;
    
    namespace WpfApp1.pages
    {
      /// <summary>
      /// Interaction logic for Page1.xaml
      /// </summary>
      public partial class Page1 : Page
      {
        public Page1()
        {
          InitializeComponent();
          this.DataContext = new Pages_ViewModel() { TbCommonText = "Introduction to Markup Languages on Page 1" };
        }
      }
    }
    

    and:

    using System.Windows.Controls;
    
    namespace WpfApp1.pages
    {
      /// <summary>
      /// Interaction logic for Page2.xaml
      /// </summary>
      public partial class Page2 : Page
      {
        public Page2()
        {
          InitializeComponent();
          this.DataContext = new Pages_ViewModel() { TbCommonText = "Introduction to Markup Languages on Page 2" };
        }
      }
    }
    
    1 person found this answer helpful.
    0 comments No comments

  3. DaisyTian-1203 11,626 Reputation points
    2020-08-31T02:40:28.287+00:00

    The below is steps for my solution:
    Step1: Create a class under your pages folder, here is its code:

    namespace WpfApp1.pages  
    {  
        public partial class DicEvent  
        {  
            private void Bt_Explain_MouseEnter(object sender, MouseEventArgs e)  
            {  
                Button TB_explain = (Button)sender;  
                TB_explain.Visibility = Visibility.Visible;  
                MessageBox.Show("This is Bt_Explain_MouseEnter event!");  
            }  
      
            private void Bt_Explain_MouseLeave(object sender, MouseEventArgs e)  
            {  
                Button TB_explain = (Button)sender;  
                TB_explain.Visibility = Visibility.Hidden;  
                MessageBox.Show("This is Bt_Explain_MouseLeave event!");  
            }  
      
            private void Bt_Preference_Click(object sender, RoutedEventArgs e)  
            {  
                Button TB_common = (Button)sender;  
                TB_common.Foreground = new SolidColorBrush(Colors.Blue);  
                MessageBox.Show("This is Bt_Preference_Click event!");  
            }  
        }  
    }  
    

    Step 2: Add x:Class="WpfApp1.pages.DicEvent" under ResourceDictionary in your dictionary1,xaml

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
                        x:Class="WpfApp1.pages.DicEvent"  
                        xmlns:local="clr-namespace:WpfApp1.pages">  
    

    Step 3: Leave the only ContentControl line code in your Page1's Grid.

    Step 4: Clean and built the project, run it and get the below result:

    21443-3.gif


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.