Share via


Názorný postup: Vytváření přenosné knihovny F#

Pomocí tohoto návodu můžete vytvořit sestavení v F#, kterou lze použít s některou aplikací Silverlight, aplikací pro tradiční stolní počítače nebo v Windows Store aplikaci, kterou vytvoříte s použitím rozhraní .NET API.Tímto způsobem můžete vytvořit uživatelské rozhraní aplikace v jiném jazyce rozhraní .NET, například v C# nebo Visual Basic, a algoritmy v jazyce F#.Můžete také podporovat různá uživatelská rozhraní určená pro různé cílové platformy.

Uživatelské rozhraní Windows Store nelze použít přímo z jazyka F#, doporučujeme tedy napsat uživatelské rozhraní pro vaši Windows Store aplikaci v jiném jazyce .NET a kód jazyka F# zapsat v přenositelné knihovně.Uživatelské rozhraní pro prostředí Silverlight a Windows Presentation Foundation (WPF) lze napsat přímo v jazyce F#, ale je možné, že budete chtít využít výhody dalších návrhových nástrojů, které jsou k dispozici, když programujete v jazyce C# nebo v kódu Visual Basic aplikace Visual Studio.

Požadavky

Chcete-li vytvořit aplikaci Windows Store, musíte mít ve vývojářském počítači systém Windows 8.

Chcete-li vytvořit projekt Silverlight, musíte mít ve vývojářském počítači program Silverlight 5.

Aplikace Tabulka

V tomto návodu vyvinete jednoduchou tabulku, které uživateli zobrazí mřížku, přičemž do buněk lze zadávat číselné vstupy a vzorce.Vrstva jazyka F# zpracovává a ověřujte veškeré vstupy a zejména analyzuje text vzorce a vypočítá výsledky vzorců.Nejprve vytvoříte algoritmický kód jazyka F#, který zahrnuje kód pro analýzu výrazů zahrnujících odkazy na buňky, čísla a matematické operátory.Tato aplikace zahrnuje také kód ke sledování, které buňky je nutné aktualizovat poté, co uživatel aktualizuje obsah jiné buňky.Poté vytvoříte uživatelská rozhraní.

Následující obrázek znázorňuje aplikaci, kterou vytvoříte v tomto návodu.

Uživatelské rozhraní aplikace Tabulka

Přenosný návod F# obrazovka závěrečné app

Tento návod obsahuje následující oddíly.

  • How To: Create an F# Portable Library

  • How To: Create a Silverlight App that Uses an F# Portable Library

  • How To: Create a ... Style App That Uses an F# Portable Library

  • How to: Create a Desktop App That References a Portable Library That Uses F#

Postupy: Vytváření knihovny F# Portable

  1. Na panelu nabídky vyberte možnosti Soubor, Nový projekt.V dialogovém okně Nový projekt rozbalte položku Visual F#, vyberte typ projektu Knihovna F# Portable a poté knihovnu pojmenujte Tabulka.Pamatujte, že projekt odkazuje na speciální verzi FSharp.Core.

  2. V Průzkumníku řešení rozbalte uzel Odkazy a poté vyberte uzel FSharp.Core.V okně Vlastnosti musí hodnota vlastnosti FullPath obsahovat položku .NETPortable, která označuje, že používáte přenositelnou verzi knihovny Core F#.Můžete také procházet různé knihovny .NET, k nimž můžete ve výchozím nastavení přistupovat.Tyto knihovny všechny fungují se společnou podmnožinou rozhraní .NET Framework, která je definovaná jako .NET Portable.Můžete odebrat odkazy, které nepotřebujete, ale pokud přidáte odkazy, vaše sestavení odkazů musí být k dispozici na všech platformách, které zamýšlíte použít.Dokumentace pro sestavení obvykle naznačuje platformy, na kterých je k dispozici.

  3. Otevřete místní nabídku projektu a poté vyberte položku Vlastnosti.Na kartě Aplikace je cílové rozhraní nastaveno na položku Podmnožina .NET Portable.Pro Visual Studio 2012 tato podmnožina cílí rozhraní .NET pro aplikace Windows Store, rozhraní .NET Framework 4.5 a Silverlight 5.Tato nastavení jsou důležitá, protože jakožto přenositelná knihovna musí vaše aplikace běžet s běhovým modulem, který je k dispozici na všech platformách.Běhové moduly pro aplikace Windows Store a Silverlight 5 obsahují podmnožiny plného rozhraní .NET Framework.

  4. Přejmenujte hlavní soubor kódu Tabulka.fs a poté vložte do okna editoru následující kód.Tento kód definuje funkci základní tabulky.

    namespace Portable.Samples.Spreadsheet
    
    open System
    open System.Collections.Generic
    
    [<AutoOpen>]
    module Extensions = 
        type HashSet<'T> with
            member this.AddUnit(v) = ignore( this.Add(v) )
    
    type internal Reference = string
    
    /// Result of formula evaluation
    [<RequireQualifiedAccess>]
    type internal EvalResult = 
        | Success of obj
        | Error of string
    
    /// Function that resolves reference to value.
    /// If formula that computes value fails, this function should also return failure.
    type internal ResolutionContext = Reference -> EvalResult
    
    /// Parsed expression
    [<RequireQualifiedAccess>]
    type internal Expression = 
        | Val of obj
        | Ref of Reference
        | Op of (ResolutionContext -> list<Expression> -> EvalResult) * list<Expression>
        with 
        member this.GetReferences() = 
            match this with
            | Expression.Ref r -> Set.singleton r
            | Expression.Val _ -> Set.empty
            | Expression.Op (_, args) -> (Set.empty, args) ||> List.fold (fun acc arg -> acc + arg.GetReferences())
    
    [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
    module internal Operations = 
        
        let eval (ctx : ResolutionContext) = 
            function
            | Expression.Val v -> EvalResult.Success v
            | Expression.Ref r -> ctx r
            | Expression.Op (f, args) -> try f ctx args with e -> EvalResult.Error e.Message
        
        type private Eval = Do 
            with 
            member this.Return(v) = EvalResult.Success v
            member this.ReturnFrom(v) = v
            member this.Bind(r, f) = 
                match r with
                | EvalResult.Success v -> f v
                | EvalResult.Error _-> r
    
        let private mkBinaryOperation<'A, 'R> (op : 'A -> 'A -> 'R) ctx =
            function
            | [a; b] -> 
                Eval.Do {
                    let! ra = eval ctx a
                    let! rb = eval ctx b
                    match ra, rb with
                    | (:? 'A as ra), (:? 'A as rb) -> return op ra rb
                    | _ -> return! EvalResult.Error "Unexpected type of argument"
                }
            | _ -> EvalResult.Error "invalid number of arguments"
    
        let add = mkBinaryOperation<float, float> (+)
        let sub = mkBinaryOperation<float, float> (-)
        let mul = mkBinaryOperation<float, float> (*)
        let div = mkBinaryOperation<float, float> (/)
    
        let ge = mkBinaryOperation<float, bool> (>=)
        let gt = mkBinaryOperation<float, bool> (>)
    
        let le = mkBinaryOperation<float, bool> (<=)
        let lt = mkBinaryOperation<float, bool> (<)
    
        let eq = mkBinaryOperation<IComparable, bool> (=)
        let neq = mkBinaryOperation<IComparable, bool> (<>)
    
        let mmax = mkBinaryOperation<float, float> max
        let mmin = mkBinaryOperation<float, float> min
    
        let iif ctx = 
            function
            | [cond; ifTrue; ifFalse] -> 
                Eval.Do {
                    let! condValue = eval ctx cond
                    match condValue with
                    | :? bool as condValue-> 
                        let e = if condValue then ifTrue else ifFalse
                        return! eval ctx e
                    | _ -> return! EvalResult.Error "Condition should be evaluated to bool"
                }
            | _ -> EvalResult.Error "invalid number of arguments"
        
        let get (name : string) = 
            match name.ToUpper() with
            | "MAX" -> mmax
            | "MIN" -> mmin
            | "IF" -> iif
            | x -> failwithf "unknown operation %s" x
    
    module internal Parser =
        let private some v (rest : string) = Some(v, rest)
        let private capture pattern text =
            let m = System.Text.RegularExpressions.Regex.Match(text, "^(" + pattern + ")(.*)")
            if m.Success then
                some m.Groups.[1].Value m.Groups.[2].Value
            else None
        let private matchValue pattern = (capture @"\s*") >> (Option.bind (snd >> capture pattern))
    
        let private matchSymbol pattern = (matchValue pattern) >> (Option.bind (snd >> Some))
        let private (|NUMBER|_|) = matchValue @"-?\d+\.?\d*"
        let private (|IDENTIFIER|_|) = matchValue @"[A-Za-z]\w*"
        let private (|LPAREN|_|) = matchSymbol @"\("
        let private (|RPAREN|_|) = matchSymbol @"\)"
        let private (|PLUS|_|) = matchSymbol @"\+"
        let private (|MINUS|_|) = matchSymbol @"-"
        let private (|GT|_|) = matchSymbol @">"
        let private (|GE|_|) = matchSymbol @">="
        let private (|LT|_|) = matchSymbol @"<"
        let private (|LE|_|) = matchSymbol @"<="
        let private (|EQ|_|) = matchSymbol @"="
        let private (|NEQ|_|) = matchSymbol @"<>"
        let private (|MUL|_|) = matchSymbol @"\*"
        let private (|DIV|_|) = matchSymbol @"/"
        let private (|COMMA|_|) = matchSymbol @","
        let private operation op args rest = some (Expression.Op(op, args)) rest
        let rec private (|Factor|_|) = function
            | IDENTIFIER(id, r) ->
                match r with
                | LPAREN (ArgList (args, RPAREN r)) -> operation (Operations.get id) args r
                | _ -> some(Expression.Ref id) r
            | NUMBER (v, r) -> some (Expression.Val (float v)) r
            | LPAREN(Logical (e, RPAREN r)) -> some e r
            | _ -> None
    
        and private (|ArgList|_|) = function
            | Logical(e, r) ->
                match r with
                | COMMA (ArgList(t, r1)) -> some (e::t) r1
                | _ -> some [e] r
            | rest -> some [] rest
    
        and private (|Term|_|) = function
            | Factor(e, r) ->
                match r with
                | MUL (Term(r, rest)) -> operation Operations.mul [e; r] rest
                | DIV (Term(r, rest)) -> operation Operations.div [e; r] rest
                | _ -> some e r
            | _ -> None
    
        and private (|Expr|_|) = function
            | Term(e, r) ->
                match r with
                | PLUS (Expr(r, rest)) -> operation Operations.add [e; r] rest
                | MINUS (Expr(r, rest)) -> operation Operations.sub [e; r] rest
                | _ -> some e r
            | _ -> None
    
        and private (|Logical|_|) = function
            | Expr(l, r) ->
                match r with
                | GE (Logical(r, rest)) -> operation Operations.ge [l; r] rest
                | GT (Logical(r, rest)) -> operation Operations.gt [l; r] rest
                | LE (Logical(r, rest)) -> operation Operations.le [l; r] rest
                | LT (Logical(r, rest)) -> operation Operations.lt [l; r] rest
                | EQ (Logical(r, rest)) -> operation Operations.eq [l; r] rest
                | NEQ (Logical(r, rest)) -> operation Operations.neq [l; r] rest
                | _ -> some l r
            | _ -> None
    
        and private (|Formula|_|) (s : string) =
            if s.StartsWith("=") then
                match s.Substring(1) with
                | Logical(l, t) when System.String.IsNullOrEmpty(t) -> Some l
                | _ -> None
            else None
    
        let parse text = 
            match text with
            | Formula f -> Some f
            | _ -> None
    
    type internal CellReference = string
    
    module internal Dependencies = 
    
        type Graph() = 
            let map = new Dictionary<CellReference, HashSet<CellReference>>()
    
            let ensureGraphHasNoCycles(cellRef) =
                let visited = HashSet()
                let rec go cycles s =
                    if Set.contains s cycles then failwith ("Cycle detected:" + (String.concat "," cycles))
                    if visited.Contains s then cycles
                    else
                    visited.AddUnit s
                    if map.ContainsKey s then
                        let children = map.[s]
                        ((Set.add s cycles), children)
                            ||> Seq.fold go
                            |> (fun cycle -> Set.remove s cycles)
                    else
                        cycles
    
                ignore (go Set.empty cellRef)
    
            member this.Insert(cell, parentCells) = 
                for p in parentCells do
                    let parentSet = 
                        match map.TryGetValue p with
                        | true, set -> set
                        | false, _ ->
                            let set = HashSet()
                            map.Add(p, set)
                            set
                    parentSet.AddUnit cell
                try 
                    ensureGraphHasNoCycles cell
                with
                    _ -> 
                    this.Delete(cell, parentCells)
                    reraise()
                                 
            member this.GetDependents(cell) = 
                let visited = HashSet()
                let order = Queue()
                let rec visit curr = 
                    if not (visited.Contains curr) then 
                        visited.AddUnit curr
                        order.Enqueue(curr)
                        match map.TryGetValue curr with
                        | true, children -> 
                            for ch in children do
                                visit ch
                        | _ -> ()
    
                        
                visit cell
                order :> seq<_>
    
            member this.Delete(cell, parentCells) = 
                for p in parentCells do
                    map.[p].Remove(cell)
                    |> ignore
    
    type Cell = 
        {
            Reference : CellReference
            Value : string
            RawValue : string
            HasError : bool
        }
    
    type RowReferences = 
        {
            Name : string
            Cells : string[]
        }
    
    type Spreadsheet(height : int, width : int) = 
        
        do 
            if height <=0 then failwith "Height should be greater than zero"
            if width <=0 || width > 26 then failwith "Width should be greater than zero and lesser than 26"
    
        let rowNames = [| for i = 0 to height - 1 do yield string (i + 1)|]
        let colNames = [| for i = 0 to (width - 1) do yield string (char (int 'A' + i)) |]
    
        let isValidReference (s : string) = 
            if s.Length < 2 then false
            else
            let c = s.[0..0]
            let r = s.[1..]
            (Array.exists ((=)c) colNames) && (Array.exists ((=)r) rowNames)
    
        let dependencies = Dependencies.Graph()
        let formulas = Dictionary<_, Expression>()
    
        let values = Dictionary()
        let rawValues = Dictionary()
    
        let setError cell text = 
            values.[cell] <- EvalResult.Error text
    
        let getValue reference = 
            match values.TryGetValue reference with
            | true, v -> v
            | _ -> EvalResult.Success 0.0
        
        let deleteValue reference = 
            values.Remove(reference)
            |> ignore
    
        let deleteFormula cell = 
            match formulas.TryGetValue cell with
            | true, expr ->
                dependencies.Delete(cell, expr.GetReferences())
                formulas.Remove(cell) 
                |> ignore
            | _ -> ()
    
        let evaluate cell = 
            let deps = dependencies.GetDependents cell
            for d in deps do
                match formulas.TryGetValue d with
                | true, e -> 
                    let r = Operations.eval getValue e
                    values.[d] <- r
                | _ -> ()
            deps
    
        let setFormula cell text = 
            let setError msg = 
                setError cell msg
                [cell] :> seq<_>
            
            try 
                match Parser.parse text with
                | Some expr ->
                    let references = expr.GetReferences()
                    let invalidReferences = [for r in references do if not (isValidReference r) then yield r]
                    if not (List.isEmpty invalidReferences) then
                        let msg = sprintf "Formula contains invalid references:%s" (String.concat ", " invalidReferences)
                        setError msg
                    else
                    try
                        dependencies.Insert(cell, references)
                        formulas.Add(cell, expr)
                        |> ignore
                        evaluate cell
                    with
                        e -> setError e.Message
                | _ -> setError "Invalid formula text"
            with e -> setError e.Message
    
        member this.Headers = colNames
        member this.Rows = rowNames
        member this.GetRowReferences() = 
            seq { for r in rowNames do
                  let cells = [| for c in colNames do yield c + r |]
                  yield { Name = r; Cells = cells } }
    
        member this.SetValue(cellRef : Reference, value : string) : Cell[] = 
            rawValues.Remove(cellRef)
            |> ignore
    
            if not (String.IsNullOrEmpty value) then
                rawValues.[cellRef] <- value
    
            deleteFormula cellRef
            
            let affectedCells = 
                if (value <> null && value.StartsWith "=") then
                    setFormula cellRef value
                elif String.IsNullOrEmpty value then
                    deleteValue cellRef
                    evaluate cellRef
                else
                    match Double.TryParse value with
                    | true, value -> 
                        values.[cellRef] <- EvalResult.Success value
                        evaluate cellRef
                    | _ -> 
                        values.[cellRef] <- EvalResult.Error "Number expected"
                        [cellRef] :> _
            [| for r in affectedCells do 
                let rawValue = 
                    match rawValues.TryGetValue r with
                    | true, v -> v
                    | false, _ -> ""
    
                let valueStr, hasErr = 
                    match values.TryGetValue r with
                    | true, (EvalResult.Success v) -> (string v), false
                    | true, (EvalResult.Error msg) -> msg, true
                    | false, _ -> "", false
                let c = {Reference = r; Value = valueStr; RawValue = rawValue; HasError = hasErr}
                yield c |]
    

Postupy: Vytvořte aplikaci Silverlight, která využívá knihovnu F# Portable

  1. Na panelu nabídky vyberte příkaz Soubor, Přidat a pak Nový projekt.V dialogovém okně Přidat nový projekt rozbalte položku Visual C#, rozbalte položku Silverlight a pak vyberte položku Aplikace Silverlight.Zobrazí se dialogové okno Nová aplikace Silverlight.

  2. Ujistěte se, že je zaškrtnuto políčko Hostovat aplikaci Silverlight na novém webu a v rozevíracím poli zkontrolujte, že je vybrána položka Projekt webové aplikace ASP.NET, a stiskněte tlačítko OK.Vytvořeny budou dva projekty; jeden projekt obsahuje ovládací prvek Silverlight a druhý projekt je webová aplikace ASP.NET, která je hostitelem ovládacích prvků.

  3. Přidejte odkaz na projekt Tabula.Otevřete místní nabídku uzlu Odkazy projektu Silverlight a poté vyberte položku Přidat odkaz.Zobrazí se Správce odkazů.Rozbalte uzel Řešení a vyberte projektu Tabulka. Poté stiskněte tlačítko OK.

  4. V tomto kroku můžete vytvořit model zobrazení, která popisuje vše, co musí uživatelské rozhraní dělat, bez popisování jeho vzhledu.Otevřete místní nabídku uzlu projektu, vyberte položku Přidat a poté položku Nová položka.Přidejte soubor kódu, pojmenujte jej ZobrazitModel.cs a poté do něj vložte následující kód:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Input;
    using Portable.Samples.Spreadsheet;
    
    namespace SilverlightFrontEnd
    {
        public class SpreadsheetViewModel
        {
            private Spreadsheet spreadsheet;
            private Dictionary<string, CellViewModel> cells = new Dictionary<string, CellViewModel>();
    
            public List<RowViewModel> Rows { get; private set; }
            public List<string> Headers { get; private set; }
    
    
            public string SourceCode
            {
                get
                {
                    return @"
    type Spreadsheet(height : int, width : int) = 
    
        do 
            if height <= 0 then failwith ""Height should be greater than zero""
            if width <= 0 || width > 26 then failwith ""Width should be greater than zero and lesser than 26""
    
        let rowNames = [| for i = 0 to height - 1 do yield string (i + 1)|]
        let colNames = [| for i = 0 to (width - 1) do yield string (char (int 'A' + i)) |]
    
        let isValidReference (s : string) = 
            if s.Length < 2 then false
            else
            let c = s.[0..0]
            let r = s.[1..]
            (Array.exists ((=)c) colNames) && (Array.exists ((=)r) rowNames)
    
        let dependencies = Dependencies.Graph()
        let formulas = Dictionary<_, Expression>()
    
        let values = Dictionary()
        let rawValues = Dictionary()
    
        let setError cell text = 
            values.[cell] <- EvalResult.E text
    
        let getValue reference = 
            match values.TryGetValue reference with
            | true, v -> v
            | _ -> EvalResult.S 0.0
    
        let deleteValue reference = 
            values.Remove(reference)
            |> ignore
    
        let deleteFormula cell = 
            match formulas.TryGetValue cell with
            | true, expr ->
                dependencies.Delete(cell, expr.GetReferences())
                formulas.Remove(cell) 
                |> ignore
            | _ -> ()
    ";
                }
            }
    
            public SpreadsheetViewModel(Spreadsheet spreadsheet)
            {
                this.spreadsheet = spreadsheet;
                Rows = new List<RowViewModel>();
                foreach (var rowRef in spreadsheet.GetRowReferences())
                {
                    var rowvm = new RowViewModel { Index = rowRef.Name, Cells = new List<CellViewModel>() };
    
                    foreach (var reference in rowRef.Cells)
                    {
                        var cell = new CellViewModel(this, reference);
                        cells.Add(reference, cell);
                        rowvm.Cells.Add(cell);
                    }
                    Rows.Add(rowvm);
    
                }
                Headers = new[] { "  " }.Concat(spreadsheet.Headers).ToList();
            }
    
            public void SetCellValue(string reference, string newText)
            {
                var affectedCells = spreadsheet.SetValue(reference, newText);
                foreach (var cell in affectedCells)
                {
                    var cellVm = cells[cell.Reference];
                    cellVm.RawValue = cell.RawValue;
    
                    if (cell.HasError)
                    {
                        cellVm.Value = "#ERROR";
                        cellVm.Tooltip = cell.Value; // will contain error
                    }
                    else
                    {
                        cellVm.Value = cell.Value;
                        cellVm.Tooltip = cell.RawValue;
                    }
                }
            }
        }
    
        public class RowViewModel
        {
            public string Index { get; set; }
            public List<CellViewModel> Cells { get; set; }
        }
    
        public class CellViewModel : INotifyPropertyChanged
        {
            private SpreadsheetViewModel spreadsheet;
    
            private string rawValue;
            private string value;
            private string reference;
            private string tooltip;
    
            public CellViewModel(SpreadsheetViewModel spreadsheet, string reference)
            {
                this.spreadsheet = spreadsheet;
                this.reference = reference;
            }
    
            public string RawValue
            {
                get
                {
                    return rawValue;
                }
                set
                {
                    var changed = rawValue != value;
                    rawValue = value;
                    if (changed) RaisePropertyChanged("RawValue");
                }
            }
            public string Value
            {
                get
                {
                    return value;
                }
                set
                {
                    var changed = this.value != value;
                    this.value = value;
                    if (changed) RaisePropertyChanged("Value");
                }
            }
            public string Tooltip
            {
                get
                {
                    return tooltip;
                }
                set
                {
                    var changed = this.tooltip != value;
                    this.tooltip = value;
                    if (changed)
                    {
                        RaisePropertyChanged("Tooltip");
                        RaisePropertyChanged("TooltipVisibility");
                    }
                }
            }
    
            public Visibility TooltipVisibility
            {
                get { return string.IsNullOrEmpty(tooltip) ? Visibility.Collapsed : Visibility.Visible; }
            }
    
            public event PropertyChangedEventHandler PropertyChanged = delegate { };
    
            public void SetCellValue(string newValue)
            {
                spreadsheet.SetCellValue(reference, newValue);
            }
    
            private void RaisePropertyChanged(string name)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
    }
    
  5. V kontrolním projektu Silverlight otevřete soubor MainPage.xaml, který určuje rozložení uživatelského rozhraní pro hlavní tabulku.V souboru MainPage.xaml vložte následující kód XAML do stávajícího prvku Mřížka.

    <TextBlock Text="{Binding SourceCode}" FontSize="20" FontFamily="Consolas" Foreground="LightGray"/>
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
          <StackPanel.Resources>
            <Style x:Key="CellBorder" TargetType="Border">
              <Setter Property="BorderThickness" Value="0.5"/>
              <Setter Property="BorderBrush" Value="LightGray"/>
            </Style>
            <Style x:Key="CaptionBorder" TargetType="Border" BasedOn="{StaticResource CellBorder}">
              <Setter Property="Background" Value="LightBlue"/>
            </Style>
            <Style x:Key="TextContainer" TargetType="TextBlock">
              <Setter Property="FontSize" Value="26"/>
              <Setter Property="FontFamily" Value="Segoe UI"/>
              <Setter Property="Width" Value="200"/>
              <Setter Property="Height" Value="60"/>
            </Style>
    
            <Style x:Key="CaptionText" TargetType="TextBlock" BasedOn="{StaticResource TextContainer}">
              <Setter Property="TextAlignment" Value="Center"/>
              <Setter Property="Foreground" Value="DimGray"/>
            </Style>
            <Style x:Key="ValueEditor" TargetType="TextBox">
              <Setter Property="Width" Value="200"/>
              <Setter Property="Height" Value="60"/>
              <Setter Property="FontSize" Value="26"/>
              <Setter Property="FontFamily" Value="Segoe UI"/>
    
            </Style>
            <Style x:Key="ValueText" TargetType="TextBlock" BasedOn="{StaticResource TextContainer}">
              <Setter Property="TextAlignment" Value="Center"/>
              <Setter Property="VerticalAlignment" Value="Center"/>
              <Setter Property="Foreground" Value="Black"/>
            </Style>
    
          </StackPanel.Resources>
          <Border Style="{StaticResource CellBorder}">
            <StackPanel>
    
              <ItemsControl ItemsSource="{Binding Headers}">
                <ItemsControl.ItemsPanel>
                  <ItemsPanelTemplate>
                    <VirtualizingStackPanel Orientation="Horizontal" />
                  </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                  <DataTemplate>
                    <Border Style="{StaticResource CaptionBorder}">
                      <TextBlock Text="{Binding}" Style="{StaticResource CaptionText}"/>
                    </Border>
                  </DataTemplate>
                </ItemsControl.ItemTemplate>
              </ItemsControl>
    
              <ItemsControl ItemsSource="{Binding Rows}">
                <ItemsControl.ItemTemplate>
                  <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                      <Border Style="{StaticResource CaptionBorder}">
                        <TextBlock Text="{Binding Index}" Style="{StaticResource CaptionText}"/>
                      </Border>
                      <ItemsControl ItemsSource="{Binding Cells}">
                        <ItemsControl.ItemsPanel>
                          <ItemsPanelTemplate>
                            <VirtualizingStackPanel  Orientation="Horizontal"/>
                          </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                        <ItemsControl.ItemTemplate>
                          <DataTemplate>
                            <Border Style="{StaticResource CellBorder}">
                              <Grid>
                                <TextBox
                                  Name="editor"
                                  Tag="{Binding ElementName=textContainer}"
                                  Visibility="Collapsed"
                                  LostFocus="OnLostFocus"
                                  KeyUp="OnKeyUp"
                                  Text ="{Binding RawValue}"
                                  Style="{StaticResource ValueEditor}"/>
                                <TextBlock
                                  Name="textContainer"
                                  Tag="{Binding ElementName=editor}"
                                  Visibility="Visible"
                                  Text="{Binding Value}"
                                  Style="{StaticResource ValueText}"
                                  MouseLeftButtonDown="OnMouseLeftButtonDown"
                                  ToolTipService.Placement="Mouse">
                                  <ToolTipService.ToolTip>
                                    <ToolTip Visibility="{Binding TooltipVisibility}">
                                      <TextBlock Text="{Binding Tooltip}" Style="{StaticResource TextContainer}" Visibility="{Binding TooltipVisibility}"/>
                                    </ToolTip>
                                  </ToolTipService.ToolTip>
                                </TextBlock>
                              </Grid>
                            </Border>
                          </DataTemplate>
                        </ItemsControl.ItemTemplate>
                      </ItemsControl>
                    </StackPanel>
                  </DataTemplate>
                </ItemsControl.ItemTemplate>
              </ItemsControl>
    
            </StackPanel>
          </Border>
        </StackPanel>
    
  6. V souboru MainPage.xaml.cs přidejte možnost using SilverlightFrontEnd; do seznamu použití direktiv a poté přidejte následující metody do třídy SilverlightApplication1.

            void OnLostFocus(object sender, RoutedEventArgs e)
            {
                var editor = (TextBox)e.OriginalSource;
                var text = editor.Text;
    
                HideEditor(e);
    
                EditValue(editor.DataContext, text);
            }
    
            void OnKeyUp(object sender, KeyEventArgs e)
            {
                if (e.Key == Key.Escape)
                {
                    HideEditor(e);
                    e.Handled = true;
                    return;
                }
                else if (e.Key == Key.Enter)
                {
                    var editor = (TextBox)e.OriginalSource;
                    var text = editor.Text;
    
                    HideEditor(e);
    
                    EditValue(editor.DataContext, text);
                    e.Handled = true;
                }
            }
    
            private void EditValue(object dataContext, string newText)
            {
                var cvm = (CellViewModel)dataContext;
                cvm.SetCellValue(newText);
            }
    
            private void OnMouseLeftButtonDown(object sender, RoutedEventArgs e)
            {
                var textBlock = (TextBlock)e.OriginalSource;
                var editor = (TextBox)textBlock.Tag;
                textBlock.Visibility = Visibility.Collapsed;
                editor.Visibility = Visibility.Visible;
                editor.Focus();
            }
    
            private void HideEditor(RoutedEventArgs e)
            {
                var editor = (TextBox)e.OriginalSource;
                var textBlock = (TextBlock)editor.Tag;
                editor.Visibility = Visibility.Collapsed;
                textBlock.Visibility = Visibility.Visible;
            }
    
  7. V souboru App.xaml.cs přidejte následující použití direktiv:

    using SilverlightFrontEnd;
    using Portable.Samples.Spreadsheet;
    

    Vložte následující kód do ovladače událostí Application_Startup:

                var spreadsheet = new Spreadsheet(5, 5);
                var spreadsheetViewModel = new SpreadsheetViewModel(spreadsheet);
                var main = new MainPage();
                main.DataContext = spreadsheetViewModel;
                this.RootVisual = main;
    
  8. Front-end Silverlight můžete testovat spuštěním přímým projektu Silverlight nebo spuštěním webové aplikace ASP.NET, která hostuje ovládací prvek Silverlight.Otevřete místní nabídku uzlu pro kterýkoli z těchto projektů a poté vyberte položku Nastavit jako spustitelný projekt.

Postupy: Vytvořte aplikaci Windows Store, která využívá knihovnu F# Portable

  1. V tomto oddílu vytvoříte aplikaci Windows Store, která využívá kód tabulky F#, který je výpočetní komponentou.Na panelu nabídky vyberte možnosti Soubor, Přidat, Nový projekt.Zobrazí se dialogové okno Nový projekt.V části Instalované rozbalte položku Visual C#, rozbalte Windows Store a poté vyberte šablonu Prázdná aplikace.Pojmenujte projekt NovyFrontEnd a stiskněte tlačítko OK.Budete-li vyzváni k zadání licence vývojáře k vytváření aplikací Windows Store, zadejte pověření.Pokud nemáte oprávnění, informace o jejich nastaveních naleznete zde.

    Projekt je vytvořen.Poznamenejte si konfiguraci a obsah tohoto projektu.Výchozí odkazy zahrnují rozhraní .NET pro aplikace Windows Store, které jsou podmnožinou rozhraní .NET Framework kompatibilního s aplikacemi systému Windows Store a sestavením systému windows, které zahrnuje rozhraní API pro běhový modul Windows Runtime a uživatelské rozhraní pro aplikace Windows Store.Vytvořeny byly podsložky Prostředky a SpolečnéPodsložka Prostředky obsahuje několik ikon, které se vztahují na aplikace Windows Store, a podsložka Společné obsahuje sdílené rutiny využívané šablonami aplikací Windows Store.Výchozí šablona projektu také vytvořila soubor App.xaml, BlankPage.xaml a jejich související soubory kódu C# App.xaml.cs a BlankPage.xaml.cs.Soubor App.xaml popisuje aplikaci jako celek a soubor BlankPage.xaml popisuje jeho jedno definované povrchové uživatelské rozhraní.A nakonec soubory PFX a APPXMANIFEST podporují modely zabezpečení a nasazení pro aplikace Windows Store.

  2. Otevřete místní nabídku uzlu Odkazy projektu Silverlight a přidejte odkaz na projekt Tabulka výběrem položky Přidat odkaz.Ve Správci odkazů rozbalte uzel Řešení, vyberte projekt Tabulka a stiskněte tlačítko OK.

  3. Budete potřebovat část kódu, kterou jste již použili v projektu Silverlight na podporu kódu pro uživatelské rozhraní aplikace Windows Store.Tento kód je obsažen v souboru ViewModels.cs.Otevřete místní nabídku uzlu projektu NovyFrontEnd, vyberte položku Přidat a poté položku Nová položka.Přidejte soubor kódu C# a pojmenujte jej ViewModels.cs.Vložte kód ze souboru ViewModels.cs do projektu Silverlight a poté změňte blok používání direktiv v horní části tohoto souboru.Odeberte položku System.Windows, která se používá pro rozhraní Silverlight, a přidejte možnosti Windows.UI.Xaml a Windows.Foundation.Collections, které se používají pro uživatelské rozhraní aplikace Windows Store.Rozhraní Silverlight a aplikace systému Windows Store jsou založena na formátu WPF, jsou tedy vzájemně kompatibilní.Aktualizovaný blok používání direktiv by se měl podobat následujícímu příkladu:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Input;
    using Portable.Samples.Spreadsheet;
    using Windows.Foundation.Collections;
    using Windows.UI.Xaml;
    

    Změňte také obor názvů v souboru ViewModels.cs z SilverlightFrontEnd na NewFrontEnd.

    Můžete znovu použít zbytek kódu v souboru ViewModels.cs, ale některé typy, například Viditelnost, jsou nyní verzemi pro aplikace systému Windows Store namísto programu Silverlight.

  4. V této aplikaci systému Windows Store musí mít soubor App.xaml.cs podobný spouštěcí kód jako kód, který se zobrazil v ovladači událostí Application_Startup pro aplikaci Silverlight.V aplikaci systému Windows Store se tento kód zobrazí v ovladači událostí OnLaunched třídy aplikací.Do ovladače událostí OnLaunched App.xaml.cs přidejte následující kód:

    var spreadsheet = new Spreadsheet(5, 5);
    var spreadsheetViewModel = new SpreadSheetViewModel(spreadsheet);
    
  5. Přidejte direktivu použití pro kód Tabulka.

    using Portable.Samples.Spreadsheet;
    
  6. V souboru App.xaml.cs zahrnuje rutina OnLaunched kód, který specifikuje stránku určenou k načtení.Přidáte požadovanou stránku, kterou má aplikace načíst po spuštění uživatelem.Změňte kód v obslužné rutině OnLaunched pro přechod na první stránku, jak znázorňuje následující příklad:

    // Create a frame, and navigate to the first page.
    var rootFrame = new Frame();
    rootFrame.Navigate(typeof(ItemsPage1), spreadsheetViewModel);
    

    Můžete odstranit soubor BlankPage1.xaml a jeho soubor kódu, protože nejsou použity v tomto příkladu.

  7. Otevřete místní nabídku uzlu projektu NovyFrontEnd, vyberte položku Přidat a poté položku Nová položka.Přidejte stránku položek a ponechejte výchozí název ItemsPage1.xaml.Tento krok přidává do projektu stránku ItemsPage1.xaml a její kódový soubor ItemsPage1.xaml.cs.Stránka ItemsPage1.xaml začíná hlavní značkou common:LayoutAwarePage s řadou atributů, jak znázorňuje následující kód XAML:

    <common:LayoutAwarePage
        x:Name="pageRoot"
        x:Class="NewFrontEnd.ItemsPage1"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:NewFrontEnd"
        xmlns:common="using:NewFrontEnd.Common"
        xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    

    Uživatelské rozhraní aplikace systému Windows Store je totožné s uživatelským rozhraní aplikace Silverlight, kterou jste vytvořili, a formát XAML je v tomto případě stejný.Kód XAML ze stránky MainPage.xaml v projektu Silverlight můžete tedy znovu použít pro soubor ItemsPage1.xaml v uživatelském rozhraní pro aplikaci systému Windows Store.

  8. Zkopírujte kód na horní úrovni prvku Mřížka souboru MainPage.xaml pro projekt Silverlight a vložte jej do prvku Mřížka horní úrovně na stránce ItemsPage1.xaml v projektu pro uživatelské rozhraní aplikace Windows Store.Vložením kódu můžete přepsat jakýkoli stávající obsah prvku Mřížka.Změňte atribut Pozadí prvku Mřížka na Bílé a nahraďte položku MouseLeftButtonDown hodnotou PointerPressed.

    Jméno této události se v různých aplikacích Silverlight a aplikacích systému Windows Store liší.

  9. Na stránce ItemsPage.xaml.cs nastavte vlastnost DataContext změnou metody OnNavigatedTo.

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        this.DataContext = e.Parameter;
    }
    
  10. Následující kód ovladače událostí zkopírujte a vložte jej do třídy ItemsPage1 OnLostFocus, OnKeyUp, EditValue, OnPointerPressed a HideEditor.

    void OnLostFocus(object sender, RoutedEventArgs e)
            {
                var editor = (TextBox)e.OriginalSource;
                var text = editor.Text;
    
                HideEditor(e);
    
                EditValue(editor.DataContext, text);
            }
    
            void OnKeyUp(object sender, KeyEventArgs e)
            {
                if (e.Key == Windows.System.VirtualKey.Escape)
                {
                    HideEditor(e);
                    e.Handled = true;
                    return;
                }
                else if (e.Key == Windows.System.VirtualKey.Enter)
                {
                    var editor = (TextBox)e.OriginalSource;
                    var text = editor.Text;
    
                    HideEditor(e);
    
                    EditValue(editor.DataContext, text);
                    e.Handled = true;
                }            
            }
    
            private void EditValue(object dataContext, string newText)
            {
                var cvm = (CellViewModel)dataContext;
                cvm.SetCellValue(newText);
            }
    
            private void OnPointerPressed(object sender, RoutedEventArgs e)
            {
                var textBlock = (TextBlock)e.OriginalSource;
                var editor = (TextBox)textBlock.Tag;
                textBlock.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
                editor.Visibility = Windows.UI.Xaml.Visibility.Visible;
    
                editor.Focus(FocusState.Programmatic);
            }
    
            private void HideEditor(RoutedEventArgs e)
            {
                var editor = (TextBox)e.OriginalSource;
                var textBlock = (TextBlock)editor.Tag;
                editor.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
                textBlock.Visibility = Windows.UI.Xaml.Visibility.Visible;
            }
    
  11. Změňte spustitelný projekt na projekt pro aplikaci systému Windows Store.Otevřete místní nabídku uzlu projektu NovyFrontEnd, vyberte položku Nastavit jako spustitelný projekt a poté spusťte projekt klávesou F5.

Vytvoření přenositelné knihovny v jazyce C#, která využívá F#

Předchozí ukázka duplikuje kód, protože kód ViewModels.cs se zobrazuje ve více projektech.V tomto oddílu vytvoříte projekt knihovny C# Portable, která bude tento kód obsahovat.V některých případech musíte do konfiguračního souboru aplikace, který využívá přenositelné knihovny využívající kód F#, přidat informace.V tomto případě aplikace pro stolní počítače zacílená na verzi rozhraní .NET Framework 4.5 pro stolní počítače odkazuje na přenositelnou knihovnu jazyka C#, která dále odkazuje na přenositelnou knihovnu F#.V takovém případě musíte přidat závazné přesměrování na soubor app.config hlavní aplikace.Toto přesměrování musíte přidat, protože je načtena pouze jedna verze knihovny FSharp.Core, nicméně přenositelné knihovny odkazují na verzi .NET Portable.Veškerá volání funkcí FSharp.Core směrovaná na verze rozhraní .NET Portable musí být přesměrována na jedinou verzi FSharp.Core, která je načtena do aplikace pro stolní počítač.Přesměrování vazby jsou potřebná pouze v aplikaci pro stolní počítač, protože běhová prostředí programu Silverlight 5 a aplikací systému Windows Store využívají verzi .NET Portable knihovny FSharp.Core, nikoli plnou verzi pro stolní počítač.

Postupy: Vytvořte aplikaci pro stolní počítač odkazující na přenositelnou knihovnu využívající jazyk F#

  1. Na panelu nabídky vyberte možnosti Soubor, Přidat, Nový projekt.V části Instalované rozbalte uzel Visual C#, vyberte šablonu projektu Knihovna .NET Portable a poté projekt pojmenujte ViewModels.

  2. Musíte nastavit cíle této knihovny .NET Portable tak, aby odpovídala knihovně F# Portable, na kterou budete přidávat odkaz.V opačném případě se zobrazí chybová zpráva s informací o neodpovídajícím odkazu.V místní nabídce projektu ViewModels vyberte položku Vlastnosti.Na kartě Knihovna změňte cíle pro přenositelnou knihovnu tak, aby odpovídaly aplikacím rozhraní .NET Framework 4.5, Silverlight 5 a Windows Store.

  3. V místní nabídce uzlu Odkazy vyberte položku Přidat odkaz.V části Řešení zaškrtněte políčko vedle tabulky.

  4. Zkopírujte kód pro soubor ViewModels.cs z některého z jiných projektů a vložte jej do souboru kódu pro projekt ViewModels.

  5. Proveďte následující změny, díky nimž bude kód v souboru ViewModels zcela nezávislý na platformě uživatelského rozhraní:

    1. Odeberte použití direktiv pro položky System.Windows, System.Windows.Input, Windows.Foundation.Collections a Windows.UI.Xaml, pokud je nastaveno.

    2. Změňte obor názvů pro projekt ViewModels.

    3. Odeberte vlastnost TooltipVisibility.Tato vlastnost využívá Viditelnost, což je objekt nezávislý na platformě.

  6. Na panelu nabídky vyberte možnosti Soubor, Přidat, Nový projekt.V části Instalované rozbalte uzel Visual C# a poté vyberte šablonu projektu Aplikace WPF.Pojmenujte nový projekt Desktop a stiskněte tlačítko OK.

  7. Otevřete místní nabídku uzlu Odkazy v projektu Desktop a vyberte položku Přidat odkaz.V části Řešení vyberte projekty Tabulka a ViewModels.

  8. Otevřete soubor app.config pro aplikaci WPF a poté přidejte následující řádky kódu.Tento kód konfiguruje příslušná přesměrování vazby, která budou použita v případě, že aplikace pro stolní počítač, která cílí na rozhraní .NET Framework 4.5, odkazuje na knihovnu .NET Portable využívající jazyk F#.Knihovny .NET Portable využívají verzi 2.3.5.0 knihovny FSharp.Core a aplikace rozhraní .NET Framework 4.5 pro stolní počítače využívají verzi 4.3.0.0.

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <startup> 
            <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
        </startup>
        <runtime>
            <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
                <dependentAssembly>
                    <assemblyIdentity name="FSharp.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
                    <bindingRedirect oldVersion="2.3.5.0" newVersion="4.3.0.0"/>
                </dependentAssembly>
            </assemblyBinding>
        </runtime>
    </configuration>
    

    Nyní musíte přidat odkaz na přenositelnou verzi knihovny F# Core.Tento odkaz je vyžadován u každé aplikace, která využívá přenositelnou knihovnu odkazující na přenositelnou knihovnu F#.

  9. Otevřete místní nabídku uzlu Odkazy v projektu Desktop a vyberte položku Přidat odkaz.Stiskněte tlačítko Procházet a poté přejděte na položku Reference Assemblies\Microsoft\FSharp\3.0\Runtime\.NETPortable\FSharp.Core.dll ve složce Program Files, ve které je nainstalována aplikace Visual Studio.

  10. V projektu Desktop přidávejte pomocí direktiv pro ViewModels.cs a Portable.Samples.Spreadsheet do App.xaml.cs a MainWindow.xaml.cs.

    using ViewModels;
    using Portable.Samples.Spreadsheet;
    
  11. Otevřete soubor MainWindow.xaml a poté změňte atribut názvu třídy Okno na Tabulka.

  12. Zkopírujte uzel v prvku Mřížka souboru MainPage.xaml v projektu Silverlight a vložte tento kód do prvku mřížka souboru MainWindow.xaml v projektu Desktop.

  13. Zkopírujte kód zpracování událostí v souboru MainPage.xaml.cs z projektu Silverlight a vložte tento kód do souboru MainWindow.xaml.cs v projektu Desktop.

            void OnLostFocus(object sender, RoutedEventArgs e)
            {
                var editor = (TextBox)e.OriginalSource;
                var text = editor.Text;
    
                HideEditor(e);
    
                EditValue(editor.DataContext, text);
            }
    
            void OnKeyUp(object sender, KeyEventArgs e)
            {
                if (e.Key == Key.Escape)
                {
                    HideEditor(e);
                    e.Handled = true;
                    return;
                }
                else if (e.Key == Key.Enter)
                {
                    var editor = (TextBox)e.OriginalSource;
                    var text = editor.Text;
    
                    HideEditor(e);
    
                    EditValue(editor.DataContext, text);
                    e.Handled = true;
                }
            }
    
            private void EditValue(object dataContext, string newText)
            {
                var cvm = (CellViewModel)dataContext;
                cvm.SetCellValue(newText);
            }
    
            private void OnMouseLeftButtonDown(object sender, RoutedEventArgs e)
            {
                var textBlock = (TextBlock)e.OriginalSource;
                var editor = (TextBox)textBlock.Tag;
                textBlock.Visibility = Visibility.Collapsed;
                editor.Visibility = Visibility.Visible;
                editor.Focus();
            }
    
            private void HideEditor(RoutedEventArgs e)
            {
                var editor = (TextBox)e.OriginalSource;
                var textBlock = (TextBlock)editor.Tag;
                editor.Visibility = Visibility.Collapsed;
                textBlock.Visibility = Visibility.Visible;
            }
    
  14. Přidejte spouštěcí kód tabulky do konstruktoru MainWindow v souboru MainWindow.xaml.cs a nahraďte odkazy na objekt MainPage odkazy na objekt MainWindow.

        public MainWindow()
        {
                var spreadsheet = new Spreadsheet(5, 5);
                var spreadsheetViewModel = new SpreadsheetViewModel(spreadsheet);
    
    
                this.DataContext = spreadsheetViewModel;
                InitializeComponent();
        }
    
  15. Otevřete místní nabídku projektu Desktop a poté vyberte položku Nastavit jako spustitelný projekt.

  16. Stisknutím klávesy F5 spusťte sestavení aplikace a poté ji dolaďte.

Další kroky

Další možností je změna projektů pro aplikaci systému Windows Store a aplikaci Silverlight a použití nové přenositelné knihovny ViewModels.

Další informace o aplikacích systému Windows Store naleznete v centru Windows Developer Center.

Viz také

Koncepty

Aplikace pro web Windows Store

Vývoj pro různé platformy s použitím rozhraní .NET Framework

Další zdroje

Vizuální F# vzorky a návody

Silverlight