简体   繁体   中英

How to use F# objects/records in C# Wpf UserControl

(Newbie question). My main application is running in F#. From the F# application, I am calling a print routine on a separate background thread. This print routine uses the below wpf xaml usercontrol in a separate C# project to format the page.

My problem is that the Account object is defined in F# and used in C# -- except that it does not work.

Error: The type 'Account' is not compatible with the type 'IAccount'

Is there anyway to have these two languages play nice together?

(Is FsXaml a possibility?)

Thanks for any help or suggestions.

TIA

F#

let workSheetHeader (a:Account) (encounterTime: Nullable<DateTime> ) = 
            let Insurance = "Self Pay"
            let firstEncounter,lastEncounter = getFirstAndLastEncounter(a,encounterTime)
            let account = {Account.birthDate = "11/30/1999"; lastName = "lastname"; firstName = "firstname"; chartNumber = 1776; doNotSee = false; mi ="i" }
            let ws =  new WorksheetHeader (account, firstEncounter, lastEncounter, Insurance)
            ws :> FrameworkElement


WPF XAML

<UserControl x:Class="StargateIX.PrintingAndReports.WorksheetHeader"
             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:StargateIX.PrintingAndReports"
             mc:Ignorable="d" 
             d:DesignHeight="70" d:DesignWidth="816">

    <UserControl.Resources>
        <!--Without the x:Key, this will style ALL the TextBlocks-->
        <Style TargetType="{x:Type TextBlock}">
            <Setter Property="FontSize" Value="12" />
        </Style>
        <Style x:Key="Title" TargetType="{x:Type TextBlock}">
            <Setter Property="FontSize" Value="14" />
            <Setter Property="TextAlignment" Value="Center" />
            <Setter Property="HorizontalAlignment" Value="Center" />
            <Setter Property="VerticalAlignment" Value="Top" />
        </Style>
    </UserControl.Resources>
    <Grid>
        <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top"  Margin="24,0" >
            <TextBlock  Text="address 1"  />
            <TextBlock  Text="address 2"     />
            <TextBlock  Text="address 3"  />
        </StackPanel>
        <StackPanel HorizontalAlignment="Right" VerticalAlignment="Top" Margin="24,0">
            <TextBlock  Text="Chart Number" Name="textblockChartNumber" />
            <TextBlock  Text="Bd: 4/15/1960" Name="textblockBirthDate"  />
            <StackPanel   Orientation="Horizontal">
                <!--Last Encounter Date-->
                <TextBlock Text="First Visit: " />
                <TextBlock Text="{Binding FirstEncounter}" />
            </StackPanel>
            <StackPanel   Orientation="Horizontal">
                <!--Last Encounter Date-->
                <TextBlock Text="Last Visit: " />
                <TextBlock Text="{Binding LastEncounter}" />
            </StackPanel>

        </StackPanel>

        <TextBlock
            Style="{StaticResource Title}" Name="textblockPatientName"
            Text="Test Name" Width="332" Margin="242,0,242,0" />

        <!--Today's Date-->
        <TextBlock x:Name="textblockTodaysDate" HorizontalAlignment="Left" Margin="368,33,0,0" Text="11/04/2015" VerticalAlignment="Top"/>

        <!--Insurance-->
        <TextBlock HorizontalAlignment="Left" Height="16" Margin="24,48,0,0" Text="{Binding Insurance}" VerticalAlignment="Top" Width="209"/>

    </Grid>
</UserControl>


Code Behind:

using System;
using System.Windows.Controls;

namespace StargateIX.PrintingAndReports
{

    public interface IAccount
    {
        string lastName { get; }
        string firstName { get; }
        string  mi { get; }
        string birthDate { get; }
        int chartNumber { get;}
        bool doNotSee { get;}
    }

    /// <summary>
    /// Interaction logic for WorksheetHeader.xaml
    /// </summary>
    public partial class WorksheetHeader : UserControl
    {
        public WorksheetHeader(IAccount account, DateTime? firstEncounter, DateTime? lastEncounter, string insurance)
        {
            DataContext = this;
            FirstEncounter = firstEncounter;
            LastEncounter = lastEncounter;
            Insurance = insurance;

            InitializeComponent();

        //    var model = new ServiceService(service);

            textblockTodaysDate.Text = DateTime.Today.ToShortDateString();
        //    textblockBirthDate.Text = $"Bd: {account.birthDate:D}";
        //    textblockChartNumber.Text = $"C#: {account.chartNumber}";
        //    textblockPatientName.Text = PatientNameService.ProperName(account);
        }
        public DateTime? FirstEncounter { get; private set; }
        public string Insurance { get; private set; }
        public DateTime? LastEncounter { get; private set; }
    }
}

#Addendum: As suggested below, I moved the definition and interface in F# to its own project, then referenced this project from the C# XAML. It now at least compiles. Here is the new definitions (in its own project):

module Contracts =

    type IAccount =
       abstract member lastName : string with get
       abstract member firstName : string with get
       abstract member mi : string with get
       abstract member birthDate: string with get
       abstract member chartNumber: int with get
       abstract member doNotSee: bool with get  
     

    type Account = 
       {
            lastName: string
            firstName: string
            mi: string
            birthDate: string
            chartNumber: int
            doNotSee: bool
       } 
       interface IAccount with
                member this.birthDate with get() = this.birthDate
                member this.chartNumber with get() = this.chartNumber
                member this.doNotSee with get() = this.doNotSee
                member this.firstName with get() = this.firstName
                member this.lastName with get() = this.lastName
                member this.mi with get() = this.mi

Is there any other way, or perhaps a better way of doing this?

TIA

If you are only exposing the interface, are not concerned about the concrete type, you can also use an object expression.

type IAccount =
    abstract member lastName : string with get
    abstract member firstName : string with get
  

 let createAccount fstName lstName =
    { new IAccount with
        member _.firstName = fstName
        member _.lastName = lstName
    }
        

A record implementing the interface is good as well. F# forces you to have acyclic dependencies, so plan ahead.

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