Monday, April 24, 2017

Thinking of using GetCallingAssembly()? Think again

When trying to run a RESTful WCF service in our UAT environment, we had a runtime error saying that an embedded resource could not be loaded. We didn't have this problem locally and also not in DEV environment. The difference between these environments is the build mode. UAT is built in Release, DEV is built in Debug. Running it in Debug mode worked fine, the exception seemed to only happen in Release mode. What made it worse was when we built a Release version and tried to debug that version, it worked fine. Long story short, we managed to narrow it down to the optimized code in Release mode ('Optimize code' check box in Visual Studio) and the use of GetCallingAssembly() in the assembly that has the embedded resource.



So what does 'Optimize code' do and why doesn't it work well with GetCallingAssembly()?

When code optimization is enabled, the JIT compiler moves codes around, for example it dynamically inlines some functions to eliminate the overhead of function calls speed. This means in runtime the optimization might change the code created by the JIT compiler, consequently returning a different assembly than what we had in mind when we decided to use GetCallingAssembly(). This is explained in an old MSDN documentation's remarks:

If the method that calls the GetCallingAssembly() method is expanded inline by the compiler (that is, if the compiler inserts the function body into the emitted Microsoft intermediate language (MSIL), rather than emitting a function call), then the assembly returned by the GetCallingAssembly() method is the assembly containing the inline code. This might be different from the assembly that contains the original method. To ensure that a method that calls the GetCallingAssembly() method is not inlined by the compiler, you can apply the MethodImplAttribute attribute with MethodImplOptions.NoInlining.


Code inlining

What is code inlining? According to wikipedia:

In computing, inline expansion, or inlining, is a manual or compiler optimization that replaces a function call site with the body of the called function

Let's illustrate this with some codes. The illustration is taken from MSDN documentation.

namespace Assembly1
{
    public Assembly Method1()
    {
        return Assembly.GetCallingAssembly();
    }
}

namespace Assembly2
{
    public Assembly Method2()
    {
        return Method1();
    }
}

namespace Assembly3
{
    public Assembly Method3()
    {
        return Method2();
    }
}

When Method1() is not inlined, GetCallingAssembly() returns Assembly2.
When Method2() is not inlined, GetCallingAssembly() returns Assembly2.

When Method1() is inlined:

namespace Assembly3
{
    public Assembly Method3()
    {
        return Method2();
    }
}

namespace Assembly2
{
    public Assembly Method2()
    {
        return Assembly.GetCallingAssembly(); // Method1() is inlined
    }
}
GetCallingAssembly() returns Assembly3.

When Method2() is inlined:

namespace Assembly3
{
    public Assembly Method3()
    {
        return Method1();  // Method2() is inlined
    }
}

namespace Assembly1
{
    public Assembly Method1()
    {
        return Assembly.GetCallingAssembly();
    }
}
GetCallingAssembly() returns Assembly3.

Conclusion

Next time you're thinking about using GetCallingAssembly(), think again. Think of how it's going to be used outside of your project. Is anyone going to enable code optimization? Because if this is the case, GetCallingAssembly() might return unexpected assembly. There are two ways to go about this:

  1. Make sure to apply MethodImplAttribute attribute with MethodImplOptions.NoInlining
  2. Use GetExecutingAssembly() instead because it's not prone to JIT inlining


Further readings

Wednesday, February 1, 2017

JavaScript First Impressions - From a C# Developer POV

The company I work for has recently decided to do web development and as someone who has mostly done desktop development and not much experience in any web development, I'm quite excited about it. I decided to start with the basic, JavaScript. I'll list some of the things I like or find interesting and also things I don't quite like or seem counter-intuitive about JavaScript. I'll put a disclaimer here that this is all my personal opinion and first impressions as a C# developer who's never had any commercial exposure to JavaScript and I might be seriously biased towards C# and unconsciously comparing it with C# with a love-hate feeling and quite possibly more hate in this case.

Like

Syntax-wise similar to C#

C# JavaScript
Variable declaration
            var x = "bla bla";
            
             var x = "bla bla";
            
Object initialisation
            var x = new 
            {
                Name = "John",
                LastName = "Doe"
            };
            
             var x = {
                name: “John”,
                lastName: “Doe”
             };
            
Class declaration
            class MyClass : MyBaseClass
            {
                ...
            }
            
            class MyClass extends MyBaseClass {
                ...
            }
            
And many others I cannot list here.

No property declaration needed

> var myObject = new Object();
> myObject.NewProperty = "hello";
hello


Dislike

Equality operators

JavaScript has two kinds of equality operators:

  • strict equality using ===
  • loose equality using ==

Both equality compares two values for equality. The == operator is called loose because two values may be considered the same even if they are of different type. The == equality converts both values to a common type (type coercion) before comparing the values. This can potentially hide bugs and many JavaScript basic tutorial articles recommends to always use === operator. If this is the case, why bother having two equality operators in the first place? I'm sure there's a reason why the == equality is introduced, but I haven't made it my priority to look into it.


Usage of this keyword

In C# this keyword would refer to the current object. A function that wants to access the value of this should be defined inside the class. All variables in C# is lexically scoped. In JavaScript this is not always the case. The value of this is determined by how a function is called i.e. the same function will have different this value depending on how it's called.

> var myObject = new Object();
> myObject.x = 0;
>
> var myFunction = function() { 
>  this.x = 55; // what is "this" here?
> };  
>
> myObject.CallFunction = myFunction;  // Now 'myObject' has a method called 'CallFunction', which is 'myFunction'.
> myObject.CallFunction();  // This executes 'myFunction', "this" now belongs to 'myObject'
> myObject.x; 
55

Weak typing

We can add number and string together for example.

> var x = "5" + 1 + 2
512
> var y = 1 + 2 + "5" + 6
356

Here we see that if we put a number in quotes, the rest of the numbers will be treated as strings and concatenated, while the previous numbers are treated as numbers. This is actually an interesting behaviour. JavaScript is smart enough to figure out what type of data we have and then make the necessary adjustments so that we don't have to redefine it. However, coming from a strongly typed language like C#, this behaviour irks me. In a strong typed language environment, the compiler will tell me right away that I'm trying to operate on two different data types. With JavaScript, I won't get any compilation error, but I could get a different result than what I expected. I know this is a rather weak argument. Developers should know the behaviour of the language they're using, but this kind of problem seems appropriate for this blog.



Conclusion

The syntax similarity to C# in my case is unfortunately misleading because it distorts my expectations of how easy it is to switch between the two languages. This is in some way reminds me of my experience learning English and Dutch as they're quite similar to me when I first started. It's quite easy to mix both English and Dutch words in a single sentence without even realising I was doing this or thinking in English while trying to speak or construct sentences in Dutch (or the other way around). Like any language, it is up to us to learn how to use the language as it's meant to be used. We should avoid falling into the trap of thinking in one language we feel more comfortable with, while we should be thinking in the other. It is a painful process, but I believe that when we invest time to become familiar with it and stop lamenting over what it is not or what it should've been, we'll start seeing the power of the language and with experience we can easily decide which language is better suited for a specific problem we're trying to solve.

Saturday, September 19, 2015

Entity Framework cannot get Column Information for Complex Types result

This link saves me:

http://stackoverflow.com/questions/7128747/ef4-the-selected-stored-procedure-returns-no-columns

I have a stored procedure that joins multiple tables, performs queries and returns a Complex Types result. When setting this up in EF designer, EF cannot detect the columns returned from the stored procedure. As Ladislav pointed out, EF needs to execute the stored procedure to actually get the column information. I choose the second solution. I hack my stored procedure to include SET FTMONLY OFF. The first solution works too until someone tries to update the model from database or if the stored procedure is adjusted to return different columns.

The problem with this, well actually the problem with my stored procedure is that there's no default parameter value specified. EF executes my stored procedure with NULL parameter resulting in error as the stored procedure expects non NULL parameter value to be passed in, so I still ended up with no column information. I finally hack my stored procedure as follows:

IF @param1 IS NULL AND @param2 IS NULL
BEGIN
   SET FTMONLY OFF
   SET @param1 = 0
   SET @param2 = '1900-01-01'
END

@param1 is an identifier and @param2 is a date. Setting identifier to 0 and date to something way in the past guarantee that there's no result returned but that's okay since we're only interested in the column information.

Saturday, August 15, 2015

Embed SSRS Report Into WPF Application Without ReportViewer

When you google how to embed SSRS report into WPF application, chances are you'd come across this page at least once:

Walkthrough: Using ReportViewer in a WPF Application

But what if you don't want to use any of Windows Form controls? ReportViewer is Windows Form control.

There is WPF WebBrowser control we potentially could use, but it doesn't have a ready built-in attribute that we could simply set an URL to, so there's an extra step needed before we can use it. An attached property will do this for us.

    public static class WebBrowserHelper
    {
        public static readonly DependencyProperty WebAddressProperty = DependencyProperty.RegisterAttached(
            "WebAddress", 
            typeof (string), 
            typeof (WebBrowserHelper), 
            new PropertyMetadata(OnWebAddressChanged));

        public static string GetWebAddress(DependencyObject dependencyObject)
        {
            return (string) dependencyObject.GetValue(WebAddressProperty);
        }

        public static void SetWebAddress(DependencyObject dependencyObject, string value)
        {
            dependencyObject.SetValue(WebAddressProperty, value);
        }

        private static void OnWebAddressChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            WebBrowser browser = d as WebBrowser;
            if (browser != null && e.NewValue != null)
            {
                string url = e.NewValue.ToString();
                browser.Navigate(url);
            }
        }
    }

To use it, simply call the attached property from WebBrowser and bind it to the SSRS URL in the ViewModel.


<UserControl x:Class="Views.WebBrowserView"
             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:Views.Helpers"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">   
    <Grid>
        <WebBrowser local:WebBrowserHelper.WebAddress="{Binding Path=SsrsUrl}" />
    </Grid>
</UserControl>

public class ViewModel
{
    public string SsrsUrl { get; set; }
}

And we're pretty much done.

Sunday, July 12, 2015

SQL Custom ORDER BY Multiple Columns

There're a lot of examples how to do custom ordering by one or multiple columns, but not for this particular case I'm working on. I need to do custom ordering based on a combination of static values across two tables.

   -------------------   ---------------
   | AssetClass      |   | AccountType |
   -------------------   ---------------
   | Equity          |   | FUT         |
   | Private Equity  |   | UIV         |
   | Credit          |   | NUIV        |
   | Macro           |   ---------------
   | Government Bond |
   -------------------

The query result should first be ordered by the AssetClass and then by the AccountType in the exact same order as shown above. Notice that neither is ordered alphabetically. An example of the result would look like something like this:

   ---------------------------------
   | AssetClass      | AccountType |
   ---------------------------------
   | Equity          | FUT         |        
   | Equity          | FUT         |
   | Equity          | FUT         |
   | Equity          | UIV         |
   | Equity          | UIV         |
   | Equity          | NUIV        |
   | Equity          | NUIV        |
   | Equity          | NUIV        |
   | Equity          | NUIV        |
   | Private Equity  | FUT         |
   | Private Equity  | FUT         |
   | Private Equity  | UIV         |
   | Private Equity  | UIV         |
   | Private Equity  | NUIV        |
   | Private Equity  | NUIV        |
   | ...             | ...         |
   | ...             | ...         |
   | ...             | ...         |
   | Government Bond | UIV         | 
   | Government Bond | UIV         |  
   | Government Bond | NUIV        |  
   | Government Bond | NUIV        |  
   | Government Bond | NUIV        |  
   ---------------------------------      
The ORDER BY statement is ugly but hey it does the job.
ORDER BY
    CASE [AssetClass]
        WHEN 'Equity' THEN
            CASE [AccountType]
                WHEN 'FUT' THEN 1
                WHEN 'UIV' THEN 2
                WHEN 'NUIV' THEN 3
                ELSE 4
            END
        WHEN 'Private Equity' THEN
            CASE [AccountType]
                WHEN 'FUT' THEN 5
                WHEN 'UIV' THEN 6
                WHEN 'NUIV' THEN 7
                ELSE 8
            END
        ...
        ...
        WHEN 'Government Bond' THEN
            CASE [AccountType]
                WHEN 'FUT' THEN 17
                WHEN 'UIV' THEN 18
                WHEN 'NUIV' THEN 19
                ELSE 20
            END
    END

Friday, June 12, 2015

SSRS Multi Value Parameter And Stored Procedure

I'm always struggling when it comes to dealing with SSRS multi value parameter. There're basically two ways of doing this:
1) Use SRRS Filter
2) Use good old SQL

I definitely prefer the first approach because it's so much simpler. All we need is a Dataset which returns result set for all possible values of the multi-value parameter and then we filter it based on the selected items. Let's say we have a Dataset called Companies with field Name. Steps to filter:

  1. Create a multi value parameter, let's call it @Company and suppose it contains the following items: AAA, BBB, CCC, which are the distinct names in field Name of the Dataset Companies.
  2. Click on Dataset Properties and select Filters in the left-hand pane
  3. In the Expression drop-down list, select Name as the field to filter
  4. In the Operator drop-down list box, select the In operator
  5. In the Value box, type in [@Company]
And you're done!

Now the second approach will involve creating a Stored Procedure that takes in one string argument, which contains the values of the selected multi-value parameter all joined together with a delimiter that we will need to parse in our Stored Procedure to be able to use it in the SQL IN clause. Using the same example as before, this string argument is something like: "AAA,BBB,CCC". In the SSRS report, on the Parameters of the query definition, we will need to set the parameter value to something like:

    =Join(Parameters!Company.Value,",")
This method is definitely more complicated. We will need to write a SQL string split function in our Stored Procedure taking into account the possibility that the delimiter is not always going to be a comma and whether we need to handle entry with white space in between.

Saturday, May 30, 2015

Windows Form MVVM databinding

I inherited a complex Windows Form UserControl that contains a DataGridView showing a matrix data structure like this.

The code behind takes care of the generation of the headers and cell values. It also takes care of the cell color scheme based on the value of the cell.

Because of the complexity and the fact that there's no out-of-the-box DataGridView implementation for WPF application, I decided to reuse this Windows Form UserControl in a WPF application I was working on. The problem is that Windows Form does not support data binding in WPF MVVM context. We will need to do the plumbing ourselves to be able to use the data binding functionality. One way to do this is as follows:

  1. Wrap the Windows Form UserControl in a WPF UserControl by using WindowsFormsHost
  2. Create DependencyProperty in this WPF UserControl, which we can use to bind to a viewmodel
  3. Use PropertyChangedCallback to modify property or state in the DataGridView control
  4. Use events in the DataGridView control to return property or state back to the DependencyProperty in the WPF UserControl

I'm posting a simple version of the original source code to illustrate this. Let's start with the business objects.

The Business Objects

    public class TenorStrikeRate
    {
        public TenorStrikeRate(string tenor, double strike, double rate)
        {
            Tenor = tenor;
            Strike = strike;
            Rate = rate;
        }

        public string Tenor { get; set; }

        public double Strike { get; set; }

        public double Rate { get; set; }
    }
    public class TenorStrikeRates : IEnumerable<TenorStrikeRate>
    {
        private readonly SortedList<Tuple<string, double>, TenorStrikeRate> internalData;

        public TenorStrikeRates()
        {
            internalData = new SortedList<Tuple<string, double>, TenorStrikeRate>();
        }

        public List<string> UniqueSortedTenors
        {
            get { return internalData.Values.Select(x => x.Tenor).Distinct().ToList(); }
        }

        public List<double> UniqueSortedStrikes
        {
            get { return internalData.Values.Select(x => x.Strike).Distinct().ToList(); }
        }

        public void Add(TenorStrikeRate toBeAddedItem)
        {
            Tuple<string, double> key = new Tuple<string, double>(toBeAddedItem.Tenor, toBeAddedItem.Strike);
            if (internalData.ContainsKey(key))
            {
                internalData.Remove(key);
            }

            internalData.Add(key, toBeAddedItem);
        }

        public TenorStrikeRate Find(string tenor, double strike)
        {
            return internalData.Values.FirstOrDefault(x => IsTenorEqual(x.Tenor, tenor) && IsDoubleEqual(x.Strike, strike));
        }

        public IEnumerator<TenorStrikeRate> GetEnumerator()
        {
            IEnumerator<TenorStrikeRate> iterator = internalData.Values.GetEnumerator();
            while (iterator.MoveNext())
            {
                yield return iterator.Current;
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj))
                return false;
            if (ReferenceEquals(this, obj))
                return true;
            if (obj.GetType() != typeof(TenorStrikeRates))
                return false;

            TenorStrikeRates other = (TenorStrikeRates)obj;
            return IsAllItemInListEqual(internalData.Values, other.internalData.Values);
        }
        
        private bool IsAllItemInListEqual(IList<TenorStrikeRate> thisList, IList<TenorStrikeRate> otherList)
        {
            bool isEqual = thisList.Count.Equals(otherList.Count);
            for (int index = 0; index < otherList.Count && isEqual; index++)
            {
                TenorStrikeRate thisItem = thisList[index];
                TenorStrikeRate otherItem = otherList[index];
                isEqual = IsTenorEqual(thisItem.Tenor, otherItem.Tenor) 
                    && IsDoubleEqual(thisItem.Strike, otherItem.Strike)
                    && IsDoubleEqual(thisItem.Rate, otherItem.Rate);
            }

            return isEqual;
        }

        private bool IsDoubleEqual(double one, double two)
        {
            if (double.IsNaN(one) && double.IsNaN(two))
            {
                return true;
            }

            return Math.Abs(one - two) < 1e-15;
        }

        private bool IsTenorEqual(string one, string two)
        {
            return one.Equals(two, StringComparison.InvariantCultureIgnoreCase);
        }
    }

The Windows Form UserControl

The Windows Form UserControl contains a DataGridView named "dgv". Set(TenorStrikeRates source) populates the DataGridView. GetDataGridSource() returns the current source state of the DataGridView. In this class we also need to declare a public event to return the current data grid source to the subscribers. A situation where we want to return the current data grid source is when users perform a data grid cell editing operation. We can then hook up this public event to the DataGridView CellEndEdit event which occurs when edit mode stops for the currently selected cell.

    public partial class DataGridViewUc : System.Windows.Forms.UserControl
    {
        public DataGridViewUc()
        {
            InitializeComponent();
        }

        public delegate void ReturnGridSourceEventHandler(TenorStrikeRates currentGridSource);

        public event ReturnGridSourceEventHandler ReturnDataGridSource;

        public void Set(TenorStrikeRates source)
        {
            dgv.Columns.Clear();
            dgv.Rows.Clear();
            if (source != null)
            {
                PopulateColumnHeader(source.UniqueSortedStrikes);
                PopulateRowHeader(source.UniqueSortedTenors);
                PopulateCells(source);
            }
        }

        public TenorStrikeRates GetDataGridSource()
        {
            TenorStrikeRates quotes = new TenorStrikeRates();
            foreach (DataGridViewColumn column in dgv.Columns)
            {
                string columnHeaderValue = column.HeaderText;
                if (columnHeaderValue != null)
                {
                    double strike = ReadStrike(columnHeaderValue);
                    foreach (DataGridViewRow row in dgv.Rows)
                    {
                        object rowHeaderValue = row.HeaderCell.Value;
                        if (rowHeaderValue != null)
                        {
                            string tenor = rowHeaderValue.ToString();
                            object rateValue = row.Cells[column.Name].Value;
                            double rate = rateValue == null ? double.NaN : Convert.ToDouble(rateValue);
                            quotes.Add(new TenorStrikeRate(tenor, strike, rate));
                        }
                    }
                }
            }

            return quotes;
        }

        private void PopulateColumnHeader(List<double> strikes)
        {
            foreach (double strike in strikes)
            {
                string headerText = strike.ToString("P2");
                dgv.Columns.Add(headerText, headerText);
            }
        }

        private void PopulateRowHeader(List<string> tenors)
        {
            int numberOfRows = tenors.Count;
            dgv.Rows.Add(numberOfRows);
            for (int i = 0; i < numberOfRows; i++)
            {
                dgv.Rows[i].HeaderCell.Value = tenors[i];
            }
        }

        private void PopulateCells(TenorStrikeRates quotes)
        {
            List<string> tenors = quotes.UniqueSortedTenors;
            List<double> strikes = quotes.UniqueSortedStrikes;
            for (int rowIdx = 0; rowIdx < tenors.Count; rowIdx++)
            {
                string optionTenor = tenors[rowIdx];
                for (int colIdx = 0; colIdx < strikes.Count; colIdx++)
                {
                    double strike = strikes[colIdx];
                    TenorStrikeRate quote = quotes.Find(optionTenor, strike);
                    if (quote != null)
                    {
                        double rate = quote.Rate;
                        DataGridViewCell cell = dgv.Rows[rowIdx].Cells[colIdx];
                        cell.Value = rate;
                    }
                }
            }
        }
        
        private double ReadStrike(string input)
        {
            string percentSymbol = Thread.CurrentThread.CurrentCulture.NumberFormat.PercentSymbol;
            input = input.Replace(percentSymbol, string.Empty);
            return double.Parse(input, Thread.CurrentThread.CurrentCulture.NumberFormat) / 100;
        }

        private void dgv_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            if (ReturnDataGridSource != null)
            {
                TenorStrikeRates newSource = GetDataGridSource(); 
                ReturnDataGridSource(newSource);
            }
        }
    }

The WPF Host

To be able to bind the DataGridView UserControl to a viewmodel, we will need to wrap it in a WPF UserControl by using WindowsFormsHost. Then we define DependencyProperty GridSource that we can bind to a property in the viewmodel. Next we define PropertyChangedCallback OnGridSourcePropertyChanged, which is called whenever GridSource property changed. In the callback, we pass in the new source to the DataGridView so it can update its display. The WPF UserControl needs to subscribe to the DataGridView's ReturnDataGridSource event to make sure any changes in the DataGridView is propagated to the WPF host layer.

XAML:


<UserControl x:Class="DataGridViewHostedInWpfControl.WpfHost.DataGridViewUcHost"
             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:DataGridViewHostedInWpfControl.WinFormLayer"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    
    <WindowsFormsHost x:Name="MyWinFormsHost">
        <local:DataGridViewUc />
    </WindowsFormsHost>

</UserControl>

Code behind:

    public partial class DataGridViewUcHost : System.Windows.Controls.UserControl
    {
        public static readonly DependencyProperty GridSourceProperty = DependencyProperty.Register(
             "GridSource",
             typeof(TenorStrikeRates),
             typeof(DataGridViewUcHost),
             new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnGridSourcePropertyChanged));

        public TenorStrikeRates GridSource
        {
            get { return (TenorStrikeRates)GetValue(GridSourceProperty); }
            set { SetValue(GridSourceProperty, value); }
        }

        private static DataGridViewUc dgvUc;

        public DataGridViewUcHost()
        {
            InitializeComponent();

            dgvUc = (DataGridViewUc)MyWinFormsHost.Child;
            dgvUc.ReturnDataGridSource += OnReturnDataGridSource;
        }

        private static void OnGridSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TenorStrikeRates newGridSource = (TenorStrikeRates)e.NewValue;
            TenorStrikeRates currentGridSource = dgvUc.GetDataGridSource();
            if (!currentGridSource.Equals(newGridSource))
            {
                dgvUc.Set(newGridSource);
            }
        }

        private void OnReturnDataGridSource(TenorStrikeRates currentGridSource)
        {
            GridSource = currentGridSource;
        }
    }

The MainWindow

Now let's build a small demo. Create a StackPanel containing the WPF control that hosts our DataGridView UserControl. Add a TextBox to the StackPanel. Everytime we change a value in the data grid, the change will be shown in the TextBox.

XAML:


<Window x:Class="DataGridViewHostedInWpfControl.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DataGridViewHostedInWpfControl.WpfHost"
        Title="MainWindow" Height="350" Width="525">
    
    <StackPanel>
        <Label Content="Input" />
        <local:DataGridViewUcHost GridSource="{Binding Input}" MinWidth="300" MinHeight="100" Margin="10" />
        <Label Content="Output" />
        <TextBox Text="{Binding Output}" />
    </StackPanel>

</Window>

Code behind:

    public partial class MainWindow : System.Windows.Window
    {
        public MainWindow()
        {
            MainViewModel vm = new MainViewModel();
            DataContext = vm;

            InitializeComponent();

            vm.Input = BuildInitialInput();
        }

        private TenorStrikeRates BuildInitialInput()
        {
            var quotes = new TenorStrikeRates();
            quotes.Add(new TenorStrikeRate("1y", -0.01, 0.01));
            quotes.Add(new TenorStrikeRate("1y", 0, 0.02));
            quotes.Add(new TenorStrikeRate("1y", 0.01, 0.03));
            quotes.Add(new TenorStrikeRate("2y", -0.01, 0.04));
            quotes.Add(new TenorStrikeRate("2y", 0, 0.05));
            quotes.Add(new TenorStrikeRate("2y", 0.01, 0.06));
            return quotes;
        }
    }

ViewModel:

    public class MainViewModel : INotifyPropertyChanged
    {
        private TenorStrikeRates input;
        public TenorStrikeRates Input
        {
            get { return input; }
            set
            {
                input = value;
                OnPropertyChanged("Input");
                Output = BuildOutputValue(value);
            }
        }

        private string output;
        public string Output
        {
            get { return output; }
            set
            {
                output = value;
                OnPropertyChanged("Output");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private string BuildOutputValue(TenorStrikeRates tenorStrikeRates)
        {
            string text = string.Empty;
            foreach (TenorStrikeRate item in tenorStrikeRates)
            {
                text = text + string.Format("Tenor: {0}, Strike: {1}, Rate: {2}\n", item.Tenor, item.Strike.ToString("P2"), item.Rate);
            }

            return text;
        }
    }

Source Code

https://github.com/velianarie/DataGridViewHostedInWpfControl