WPF ContextMenu independent visual tree resolved via Freezable implemented class

public class ProxyBinding : Freezable
{

    public object DataSource
    {
        get { return (object)GetValue(DataSourceProperty); }
        set { SetValue(DataSourceProperty, value); }
    }

    // Using a DependencyProperty as the backing store for DataSource.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty DataSourceProperty =
        DependencyProperty.Register(
            nameof(DataSource),
            typeof(object),
            typeof(ProxyBinding), new PropertyMetadata(null));


    public ProxyBinding()
    {

    }

    protected override Freezable CreateInstanceCore()
    {
        return new ProxyBinding();
    }
}



        <local:ProxyBinding x:Key="DataContextProxy"
                            DataSource="{Binding}"/>



<ContextMenu>
    <MenuItem Header="Load Data In Grid"
              FontSize="20"
              Width="300"
              Command="{Binding DataSource.LoadDataCommand,Source={StaticResource DataContextProxy}}"
              CommandParameter="10000"/>
</ContextMenu>

 

<Window x:Class="WpfApp10.MainWindow"
        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:WpfApp10"
        mc:Ignorable="d"
        Title="MainWindow" WindowState="Maximized">
    <Window.DataContext>
        <local:MainVM/>
    </Window.DataContext>
    <Window.Resources>
        <Style TargetType="TextBlock" x:Key="TbkStyle">
            <Setter Property="FontSize" Value="30"/>
            <Setter Property="FontWeight" Value="Normal"/>
            <Setter Property="HorizontalAlignment" Value="Center"/>
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Foreground" Value="Red"/>
                </Trigger>
            </Style.Triggers>
        </Style>

        <local:ProxyBinding x:Key="DataContextProxy"
                            DataSource="{Binding}"/>

        <DataTemplate DataType="{x:Type local:Book}" x:Key="BookRowDataTemplate">
            <Border BorderBrush="LightGray"
                    BorderThickness="2"
                    Margin="5">
                <Grid>
                    <Grid.Resources>
                        <Style TargetType="TextBlock" BasedOn="{StaticResource TbkStyle}"/>
                    </Grid.Resources>
                    <Grid.RowDefinitions>
                        <RowDefinition/>
                        <RowDefinition/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="4*"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="{Binding Id}" Grid.Row="0" Grid.Column="0"/>
                    <TextBlock Text="{Binding Name}" Grid.Row="0" Grid.Column="1"/>
                    <TextBlock Text="{Binding ISBN}" Grid.Row="0" Grid.Column="2"/>
                    <TextBlock Text="{Binding Summary}" Grid.Row="1" Grid.Column="0"/>
                    <TextBlock Text="{Binding Title}" Grid.Row="1" Grid.Column="1"/>
                    <TextBlock Text="{Binding Topic}" Grid.Row="1" Grid.Column="2"/>
                    <Grid.ContextMenu>
                        <ContextMenu>
                            <MenuItem Header="Load Data In Grid"
                                      FontSize="20"
                                      Width="300"
                                      Command="{Binding DataSource.LoadDataCommand,Source={StaticResource DataContextProxy}}"
                                      CommandParameter="10000"/>
                        </ContextMenu>
                    </Grid.ContextMenu>
                </Grid>
            </Border>
        </DataTemplate>

        <DataTemplate DataType="{x:Type local:GroupedBook}" x:Key="GroupBookDataTemplate">
            <GroupBox BorderBrush="Cyan"
                      Header="{Binding GroupName}"
                      FontSize="50"
                    BorderThickness="2"
                    Margin="10">
                <ItemsControl ItemsSource="{Binding BksList}"
                              ItemTemplate="{StaticResource BookRowDataTemplate}">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <VirtualizingStackPanel/>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                </ItemsControl>
            </GroupBox>
        </DataTemplate>

        <ControlTemplate TargetType="ContentControl" x:Key="ContentControlTemplate">
            <ScrollViewer>
                <ItemsControl ItemsSource="{Binding GroupedBooks}"
              ItemTemplate="{StaticResource GroupBookDataTemplate}">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <VirtualizingStackPanel/>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                    <ItemsControl.ContextMenu>
                        <ContextMenu>
                            <MenuItem Header="Load Data"
                                      Width="300"
                                      FontSize="30"
                                      Command="{Binding LoadDataCommand}"/>
                        </ContextMenu>
                    </ItemsControl.ContextMenu>
                </ItemsControl>
            </ScrollViewer>
        </ControlTemplate>
    </Window.Resources>
    <Grid>
        <ContentControl Template="{StaticResource ContentControlTemplate}"/>
    </Grid>
</Window>



using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;
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;

namespace WpfApp10
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }

    public class MainVM : INotifyPropertyChanged
    {
        private WcfService5.BookService bkService;
        public MainVM()
        {
            if (!DesignerProperties.GetIsInDesignMode(new DependencyObject()))
            {
                bkService = new WcfService5.BookService();

                InitBooks(100);
            }
        }

        private ICommand loadDataCommand;
        public ICommand LoadDataCommand
        {
            get
            {
                if (loadDataCommand == null)
                {
                    loadDataCommand = new DelegateCommand(LoadCommandExecuted);
                }
                return loadDataCommand;
            }
        }

        private void LoadCommandExecuted(object? obj)
        {
            if (int.TryParse(obj?.ToString(), out int num))
            {
                InitBooks(num);
            }
        }

        private void InitBooks(int cnt = 1000)
        {
            var bks = GetBooks(cnt);
            var groupedBks = bks.GroupBy(x => x.CategoryName);
            GroupedBooks = new ObservableCollection<GroupedBook>();
            foreach (var g in groupedBks)
            {
                GroupedBooks.Add(new GroupedBook()
                {
                    GroupName = g.Key,
                    BksList = g.ToList()
                });
            }
        }

        private List<Book> GetBooks(int cnt)
        {
            var bksList = bkService.GetBooks(cnt).Select(x => new Book()
            {
                Id = x.Id,
                Name = x.Name,
                ISBN = x.ISBN,
                Summary = x.Summary,
                Title = x.Title,
                Topic = x.Topic,
                CategoryName = x.CategoryName
            }).ToList();
            return bksList;
        }

        private ObservableCollection<GroupedBook> groupedBooks;
        public ObservableCollection<GroupedBook> GroupedBooks
        {
            get
            {
                return groupedBooks;
            }
            set
            {
                if (value != groupedBooks)
                {
                    groupedBooks = value;
                    OnPropertyChanged();
                }
            }
        }

        public event PropertyChangedEventHandler? PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName = "")
        {
            var handler = Volatile.Read(ref PropertyChanged);
            if (handler == null)
            {
                return;
            }
            handler(this, new PropertyChangedEventArgs(propName));
        }
    }

    public class GroupedBook
    {
        public string GroupName { get; set; }
        public List<Book> BksList { get; set; }
    }

    public class Book
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public string ISBN { get; set; }
        public string CategoryName { get; set; }
        public string Summary { get; set; }
        public string Title { get; set; }
        public string Topic { get; set; }
    }

    public class DelegateCommand : ICommand
    {
        private Action<object?> execute;
        private Func<object?, bool>? canExecute;

        public DelegateCommand(Action<object?> executeValue, Func<object?, bool>? canExecuteValue = null)
        {
            execute = executeValue ?? throw new ArgumentNullException(nameof(executeValue));
            canExecute = canExecuteValue;
        }

        public event EventHandler? CanExecuteChanged;

        public bool CanExecute(object? parameter)
        {
            return canExecute == null ? true : canExecute(parameter);
        }

        public void Execute(object? parameter)
        {
            execute(parameter);
        }

        public void RaiseCanExecuteChanged()
        {
            var handler = Volatile.Read(ref CanExecuteChanged);
            if (handler == null)
            {
                return;
            }

            var dispatcher = Application.Current?.Dispatcher;
            if (dispatcher != null)
            {
                if (dispatcher.CheckAccess())
                {
                    handler(this, EventArgs.Empty);
                }
                else
                {
                    dispatcher.Invoke(() =>
                    {
                        handler(this, EventArgs.Empty);
                    }, System.Windows.Threading.DispatcherPriority.Background);
                }
            }
        }
    }

    public class ProxyBinding : Freezable
    {

        public object DataSource
        {
            get { return (object)GetValue(DataSourceProperty); }
            set { SetValue(DataSourceProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DataSource.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DataSourceProperty =
            DependencyProperty.Register(
                nameof(DataSource),
                typeof(object),
                typeof(ProxyBinding), new PropertyMetadata(null));


        public ProxyBinding()
        {

        }

        protected override Freezable CreateInstanceCore()
        {
            return new ProxyBinding();
        }
    }
}

 

 

 

 

 

image

 

 

 

 

 

 

image

 

 

 

 

WCF

//WCF
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WcfService5
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IBookService" in both code and config file together.
    [ServiceContract]
    public interface IBookService
    {
        [OperationContract]
        [WebGet(UriTemplate ="/getbooks?cnt={cnt}")]
        List<Book> GetBooks(int cnt = 1000);
    }

    public class Book
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public string ISBN { get; set; }
        public string CategoryName { get; set; }
        public string Summary { get; set; }
        public string Title { get; set; }
        public string Topic { get; set; }
    }

    enum BookCategory
    {
        Science, Technology, Engineering, Math
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Threading;

namespace WcfService5
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "BookService" in code, svc and config file together.
    // NOTE: In order to launch WCF Test Client for testing this service, please select BookService.svc or BookService.svc.cs at the Solution Explorer and start debugging.
    public class BookService : IBookService
    {
        private static long id = 1;
        private static string[] enumNames = Enum.GetNames(typeof(BookCategory));
        private static int enumsLength = enumNames.Length;
        private static Random rnd = new Random();

        private static (long, long) GetStartEnd(int interval = 1000)
        {
            long end = Interlocked.Add(ref id, interval);
            long start = end - interval;
            return (start, end);
        }

        public List<Book> GetBooks(int cnt = 1000)
        {
            List<Book> bksList = new List<Book>();
            var (start, end) = GetStartEnd(cnt);
            for (long i = start; i < end; i++)
            {
                bksList.Add(new Book()
                {
                    Id = i,
                    Name = $"Name_{i}",
                    CategoryName = enumNames[rnd.Next(enumsLength)],
                    Summary = $"Summary_{i}",
                    ISBN = $"ISBN_{i}_{Guid.NewGuid():N}",
                    Title = $"Title_{i}",
                    Topic = $"Topic_{i}"
                });
            }
            return bksList;
        }
    }
}


<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
  </appSettings>
  <!--
    For a description of web.config changes see http://go.microsoft.com/fwlink/?LinkId=235367.

    The following attributes can be set on the <httpRuntime> tag.
      <system.Web>
        <httpRuntime targetFramework="4.8" />
      </system.Web>
  -->
  <system.web>
    <compilation debug="true" targetFramework="4.8"/>
    <httpRuntime targetFramework="4.7.2"/>
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
      <add binding="basicHttpsBinding" scheme="https"/>
    </protocolMapping>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled="true"/>
  </system.webServer>
</configuration>

 

 

Add  Project reference of WCF  project

 

posted @ 2026-08-15 14:14  FredGrit  阅读(2)  评论(0)    收藏  举报