Exemplarische Vorgehensweise: Erstellen einer portablen F#-Bibliothek

Mithilfe dieser exemplarischen Vorgehensweise können Sie eine Assembly in F# erstellen, die Sie für eine Silverlight-App, eine herkömmliche Desktop-App oder eine Windows Store-App verwenden können, die Sie mit .NET-APIs erstellen.Auf diese Weise können Sie den Benutzeroberflächenteil der App in einer anderen .NET-Sprache, z. B. C# oder Visual Basic, und den Algorithmusteil in F# schreiben.Sie können außerdem unterschiedliche Benutzeroberflächen für verschiedene Plattformen unterstützen.

Die Windows Store-Benutzeroberfläche kann nicht direkt in F# verwendet werden. Daher empfiehlt es sich, die Benutzeroberfläche für Ihre Windows Store-App in einer anderen .NET-Sprache zu schreiben, den F#-Code dagegen in eine portable Bibliothek.Sie können Silverlight- und WPF (Windows Presentation Foundation)-Benutzeroberflächen direkt in F# schreiben. Sie sollten jedoch die zusätzlichen Entwurfstools nutzen, die verfügbar sind, wenn Sie C#- oder Visual Basic-Code in Visual Studio schreiben.

Vorbereitungsmaßnahmen

Zum Erstellen einer Windows Store-App muss auf dem Entwicklungscomputer Windows 8 installiert sein.

Zum Erstellen eines Silverlight-Projekts muss auf dem Entwicklungscomputer Silverlight 5 installiert sein.

Die Spreadsheet-App

In dieser exemplarischen Vorgehensweise entwickeln Sie ein einfaches Arbeitsblatt, das für den Benutzer ein Raster darstellt und numerische Eingaben und Formeln in den Zellen akzeptiert.Auf der F#-Ebene erfolgen Verarbeitung und Überprüfung aller Eingaben, die Analyse des Formeltexts und die Berechnung der Formelergebnisse.Zunächst erstellen Sie den algorithmischen F#-Code, darunter Code zum Analysieren von Ausdrücken, die Zellenverweise, Zahlen und mathematische Operatoren enthalten.Diese App enthält auch den Code, der nachverfolgt, welche Zellen aktualisiert werden müssen, wenn ein Benutzer den Inhalt einer anderen Zelle aktualisiert.Anschließend erstellen Sie die Benutzeroberflächen.

Die folgende Abbildung zeigt die Anwendung, die Sie in dieser exemplarischen Vorgehensweise erstellen.

Benutzeroberfläche der Spreadsheet-App

F# Screenshot mit übertragbarer Vorgehensweise zur endgültigen App

Diese exemplarische Vorgehensweise enthält die folgenden Abschnitte.

  • 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#

Gewusst wie: Erstellen einer portablen F#-Bibliothek

  1. Wählen Sie auf der Menüleiste Datei, Neues Projekt aus.Erweitern Sie im Dialogfeld Neues Projekt den Eintrag Visual F#, wählen Sie den Projekttyp Portable F#-Bibliothek aus, und geben Sie der Bibliothek den Namen Spreadsheet.Beachten Sie, dass es sich bei den Projektverweisen um eine spezielle Version von FSharp.Core handelt.

  2. Erweitern Sie im Projektmappen-Explorer den Knoten Verweise, und wählen Sie dann den Knoten FSharp.Core aus.Im Fenster Eigenschaften sollte der Wert der FullPath-Eigenschaft die Zeichenfolge .NETPortable enthalten, um anzugeben, dass Sie die portable Version der F#-Kernbibliothek verwenden.Sie können auch die verschiedenen .NET-Bibliotheken überprüfen, auf die Sie standardmäßig Zugriff haben.Alle diese Bibliotheken verwenden die gleiche Teilmenge von .NET Framework, die als portables .NET definiert ist.Sie können nicht benötigte Verweise entfernen; wenn Sie jedoch Verweise hinzufügen, muss die Verweisassembly auf allen Zielplattformen verfügbar sein.Die Dokumentation für eine Assembly gibt normalerweise die Plattformen an, auf denen sie verfügbar ist.

  3. Öffnen Sie das Kontextmenü für das Projekt, und wählen Sie dann Eigenschaften aus.Auf der Registerkarte Anwendung ist das Zielframework auf .NET Portable Subset festgelegt.In Visual Studio 2012 gilt diese Teilmenge für .NET für Windows Store-Apps, .NET Framework 4.5 und Silverlight 5.Diese Einstellungen sind wichtig, da die App als portable Bibliothek für die Laufzeit ausgeführt werden muss, die auf verschiedenen Plattformen verfügbar ist.Die Laufzeiten für Windows Store-Apps und Silverlight 5 enthalten Teilmengen von .NET Framework.

  4. Benennen Sie die Hauptcodedatei mit Spreadsheet.fs, und fügen Sie dann im Editorfenster den folgenden Code ein.Dieser Code definiert die Funktionen eines einfachen Arbeitsblatts.

    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 |]
    

Gewusst wie: Erstellen einer Silverlight-App, die eine portable F#-Bibliothek verwendet

  1. Wählen Sie auf der Menüleiste Datei, Hinzufügen und dann Neues Projekt aus.Erweitern Sie im Dialogfeld Neues Projekt hinzufügen den Eintrag Visual C#, erweitern Sie Silverlight, und wählen Sie dann Silverlight-Anwendung aus.Das Dialogfeld Neue Silverlight-Anwendung wird angezeigt.

  2. Stellen Sie sicher, dass das Kontrollkästchen Die Silverlight-Anwendung in einer neuen Website hosten aktiviert ist und dass in der Dropdownliste der Eintrag ASP.NET-Webanwendungsprojekt ausgewählt ist, und wählen Sie dann die Schaltfläche OK.Es werden zwei Projekte erstellt: Ein Projekt verfügt über das Silverlight-Steuerelement, und das andere Projekt ist eine ASP.NET-Webanwendung, die das Steuerelement hostet.

  3. Fügen Sie dem Projekt Spreadsheet einen Verweis hinzu.Öffnen Sie das Kontextmenü für den Knoten Verweise des Silverlight-Projekts, und wählen Sie dann Verweis hinzufügen aus.Der Verweis-Manager wird angezeigt.Erweitern Sie den Knoten Projektmappe, wählen Sie das Projekt Spreadsheet aus, und klicken Sie dann auf OK.

  4. In diesem Schritt erstellen Sie ein Ansichtsmodell, in dem alle Aktionen beschrieben werden, die durch die Benutzeroberfläche ausgeführt werden müssen, ohne zu beschreiben, wie die Benutzeroberfläche dargestellt wird.Öffnen Sie das Kontextmenü für den Projektknoten, und wählen Sie Hinzufügen und dann Neues Element aus.Fügen Sie eine Codedatei hinzu, benennen Sie diese mit ViewModel.cs, und fügen Sie dann den folgenden Code in die Datei ein:

    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. Öffnen Sie im Projekt mit dem Silverlight-Steuerelement die Datei MainPage.xaml, die das Benutzeroberflächenlayout für das Hauptarbeitsblatt deklariert.Fügen Sie in MainPage.xaml den folgenden XAML-Code in das vorhandene Grid-Element ein.

    <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. Fügen Sie in MainPage.xaml.cs der Liste der using-Direktiven using SilverlightFrontEnd; hinzu, und fügen Sie dann der SilverlightApplication1-Klasse die folgenden Methoden hinzu.

            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. Fügen Sie in App.xaml.cs die folgenden using-Direktiven hinzu:

    using SilverlightFrontEnd;
    using Portable.Samples.Spreadsheet;
    

    Fügen im Application_Startup-Ereignishandler folgenden Code hinzu:

                var spreadsheet = new Spreadsheet(5, 5);
                var spreadsheetViewModel = new SpreadsheetViewModel(spreadsheet);
                var main = new MainPage();
                main.DataContext = spreadsheetViewModel;
                this.RootVisual = main;
    
  8. Sie können das Silverlight-Front-End testen, indem Sie entweder direkt das Silverlight-Projekt starten oder indem Sie die ASP.NET-Webanwendung starten, die das Silverlight-Steuerelement hostet.Öffnen Sie das Kontextmenü des Knotens für eines dieser Projekte, und wählen Sie dann Als Startprojekt festlegen aus.

Gewusst wie: Erstellen einer Windows Store-App, die eine übertragbare F#-Bibliothek verwendet

  1. In diesem Abschnitt erstellen Sie eine Windows Store-App, die den F#-Arbeitsblattcode als Berechnungskomponente verwendet.Wählen Sie auf der Menüleiste Datei, Hinzufügen, Neues Projekt aus.Das Dialogfeld Neues Projekt wird angezeigt.Die InstalliertVisual C# erweitern Sie, erweitern Sie Windows Store und dann die Vorlage aus. Leere AppGeben Sie dem Projekt den Namen "NewFrontEnd" und wählen Sie dann die Schaltfläche OK.Wenn Sie nach Ihrer Entwicklerlizenz zum Erstellen von Windows Store-Apps gefragt werden, geben Sie Ihre Anmeldeinformationen ein.Wenn Sie über keine Anmeldeinformationen verfügen, erfahren Sie hier, wie Sie diese einrichten.

    Das Projekt wird erstellt.Beachten Sie die Konfiguration und den Inhalt dieses Projekts.Die standardmäßige Verweise enthalten .NET für Windows Store-Apps, das die Teilmenge von .NET Framework ist, die mit Windows Store-App kompatibel ist, und die Windows-Assembly, die die API während Windows Runtime und die Benutzeroberfläche für Windows Store-App umfasst.Die Unterordner Assets und Common wurden erstellt.Der Unterordner Assets enthält einige Symbole für Windows Store-Apps, und der Unterordner Common enthält Routinen, die von Vorlagen für Windows Store-Apps gemeinsam genutzt werden.Mit der Standardprojektvorlage wurden außerdem App.xaml, BlankPage.xaml und die entsprechenden Code-Behind-Dateien App.xaml.cs und BlankPage.xaml.cs für C# erstellt.App.xaml beschreibt die gesamte App, und BlankPage.xaml beschreibt die einzige definierte Benutzeroberfläche der App.Schließlich unterstützen alle PFX- und APPXMANIFEST-Dateien die Sicherheit- und Bereitstellungsmodelle für Windows Store-Apps.

  2. Fügen Sie dem Projekt Spreadsheet einen Verweis hinzu, indem Sie das Kontextmenü für den Knoten Verweise des Silverlight-Projekts öffnen und Verweis hinzufügen auswählen.Erweitern Sie im Verweis-Manager den Knoten Projektmappe, wählen Sie das Projekt Spreadsheet aus, und klicken Sie dann auf OK.

  3. Zur Unterstützung des Codes für die Benutzeroberfläche der Windows Store-App benötigen Sie einen Teil des Codes, den Sie bereits im Silverlight-Projekt verwendet haben.Dieser Code befindet sich in ViewModels.cs.Öffnen Sie das Kontextmenü des Projektknotens für NewFrontEnd, wählen Sie Hinzufügen und dann Neues Element aus.Fügen Sie eine C#-Codedatei hinzu, und benennen Sie sie mit ViewModels.cs.Fügen Sie den Code aus ViewModels.cs im Silverlight-Projekt ein, und ändern Sie dann am Anfang dieser Datei den Block der using-Direktiven.Entfernen Sie System.Windows, das für die Silverlight-Benutzeroberfläche verwendet wird, und fügen Sie Windows.UI.Xaml und Windows.Foundation.Collections hinzu, die für die Benutzeroberfläche der Windows Store-App verwendet werden.Sowohl die Silverlight-Benutzeroberfläche als auch die Benutzeroberfläche der Windows Store-App basieren auf WPF und sind daher zueinander kompatibel.Der aktualisierte Block der using-Direktiven sollte dem folgenden Beispiel entsprechen:

    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;
    

    Ändern Sie außerdem in ViewModels.cs den Namespace von SilverlightFrontEnd in NewFrontEnd.

    Sie können den restlichen Code in ViewModels.cs wiederverwenden, jedoch sind jetzt einige Typen, z. B. Visibility, die Versionen für Windows Store-Apps statt für Silverlight.

  4. In dieser Windows Store-App muss der Startcode der Codedatei App.xaml.cs dem Startcode im Application_Startup-Ereignishandler für die Silverlight-App entsprechen.In einer Windows Store-App ist dieser Code im OnLaunched-Ereignishandler der App-Klasse enthalten.Fügen Sie dem OnLaunched-Ereignishandler in App.xaml.cs folgenden Code hinzu:

    var spreadsheet = new Spreadsheet(5, 5);
    var spreadsheetViewModel = new SpreadSheetViewModel(spreadsheet);
    
  5. Fügen Sie eine using-Direktive für den Code der Spreadsheet-App hinzu.

    using Portable.Samples.Spreadsheet;
    
  6. In App.xaml.cs enthält OnLaunched Code, der angibt, welche Seite geladen werden soll.Sie fügen eine Seite hinzu, die von der App geladen werden soll, wenn sie von einem Benutzer gestartet wird.Ändern Sie den Code in OnLaunched, um zur ersten Seite zu navigieren, wie im folgenden Beispiel gezeigt:

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

    Sie können BlankPage1.xaml und die zugehörige Code-Behind-Datei löschen, da sie in diesem Beispiel nicht verwendet werden.

  7. Öffnen Sie das Kontextmenü des Projektknotens für NewFrontEnd, wählen Sie Hinzufügen und dann Neues Element aus.Fügen Sie eine Elementseite hinzu, und behalten Sie den Standardnamen ItemsPage1.xaml bei.Mit diesem Schritt werden dem Projekt ItemsPage1.xaml und die zugehörige Code-Behind-Datei ItemsPage1.xaml.cs hinzugefügt.ItemsPage1.xaml beginnt mit dem Haupttag common:LayoutAwarePage, auf den viele Attribute folgen, wie der folgenden XAML-Code zeigt:

    <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">
    

    Die Benutzeroberfläche für die Windows Store-App ist mit der Benutzeroberfläche für die von Ihnen erstellte Silverlight-App identisch, und das XAML-Format ist in diesem Fall das Gleiche.Daher können Sie das XAML aus MainPage.xaml im Silverlight-Projekt für ItemsPage1.xaml in der Benutzeroberfläche für die Windows Store-App wiederverwenden.

  8. Kopieren Sie den Code im Grid-Element der obersten Ebene von MainPage.xaml für das Silverlight-Projekt, und fügen Sie ihn im Projekt für die Benutzeroberfläche der Windows Store-App in das Grid-Element der obersten Ebene in ItemsPage1.xaml ein.Wenn Sie den Code einfügen, können Sie ggf. vorhandenen Inhalt des Grid-Elements überschreiben.Ändern Sie das Background-Attribut des Grid-Elements in "White", und ersetzen Sie MouseLeftButtonDown durch PointerPressed.

    Der Name dieses Ereignisses ist in Silverlight-Apps und Windows Store-Apps unterschiedlich.

  9. Legen Sie in ItemsPage.xaml.cs die DataContext-Eigenschaft fest, indem Sie die OnNavigatedTo-Methode ändern.

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        this.DataContext = e.Parameter;
    }
    
  10. Kopieren Sie den folgenden Ereignishandlercode, und fügen Sie ihn in die ItemsPage1-Klasse ein: OnLostFocus, OnKeyUp, EditValue, OnPointerPressed und 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. Legen Sie das Projekt für die Windows Store-App als Startprojekt fest.Öffnen Sie das Kontextmenü für den Projektknoten NewFrontEnd, wählen Sie Als Startprojekt festlegen, und drücken Sie dann die Taste F5, um das Projekt auszuführen.

Erstellen einer portablen Bibliothek in C#, die F# verwendet

Das vorherige Beispiel enthält mehrfach den gleichen Code, da der Code von ViewModels.cs in mehreren Projekten verwendet wird.In diesem Abschnitt erstellen Sie ein portables C#-Bibliotheksprojekt, das diesen Code enthält.In manchen Fällen müssen Sie der Konfigurationsdatei einer App Informationen hinzufügen, wenn sie portable Bibliotheken nutzt, die F# verwenden.In diesem Fall verweist eine Desktop-App für die Desktopversion von .NET Framework 4.5 auf eine portable C#-Bibliothek, die wiederum auf eine portable F#-Bibliothek verweist.In einem solchen Fall müssen Sie der Datei app.config der Haupt-App eine bindende Umleitung hinzufügen.Sie müssen diese Umleitung hinzufügen, da nur eine Version der FSharp.Core-Bibliothek geladen wird, die portablen Bibliotheken jedoch auf die portable .NET-Version verweisen.Alle Aufrufe der portablen .NET-Versionen von FSharp.Core-Funktionen müssen zu der einzelnen Version von FSharp.Core umgeleitet werden, die in einer Desktop-App geladen wird.Die Bindungsumleitungen sind nur in der Desktop-App erforderlich, da die Laufzeitumgebungen für Silverlight 5-Apps und Windows Store-Apps die Version .NET Portable von FSharp.Core verwenden und nicht die vollständige Desktopversion.

Gewusst wie: Erstellen einer Desktop-App, die auf eine portable Bibliothek verweist, die F# verwendet

  1. Wählen Sie auf der Menüleiste Datei, Hinzufügen, Neues Projekt aus.Erweitern Sie unter Installiert den Knoten Visual C#, wählen Sie die Projektvorlage Portable .NET-Bibliothek aus, und benennen Sie das Projekt mit ViewModels.

  2. Sie müssen die Zielplattformen für diese portable .NET-Bibliothek entsprechend der portablen F#-Bibliothek festlegen, der Sie einen Verweis hinzufügen.Andernfalls informiert Sie eine Fehlermeldung über den Konflikt.Wählen Sie im Kontextmenü für das Projekt ViewModels die Option Eigenschaften aus.Ändern Sie auf der Registerkarte Bibliothek die Ziele für diese übertragbare Bibliothek, damit sie in .NET Framework 4.5-Apps, Silverlight 5-Apps und Windows Store-Apps verwendbar ist.

  3. Wählen Sie im Kontextmenü für den Knoten Verweise die Option Verweis hinzufügen aus.Aktivieren Sie unter Projektmappe das Kontrollkästchen neben Spreadsheet.

  4. Kopieren Sie den Code für ViewModels.cs aus einem der anderen Projekte, und fügen Sie ihn in der Codedatei für das Projekt ViewModels ein.

  5. Nehmen Sie die folgenden Änderungen vor, durch die der Code in ViewModels vollkommen unabhängig von der Benutzeroberflächenplattform wird:

    1. Entfernen Sie die using-Direktiven für System.Windows, System.Windows.Input, Windows.Foundation.Collections und Windows.UI.Xaml, falls vorhanden.

    2. Ändern Sie den Namespace in ViewModels.

    3. Entfernen Sie die TooltipVisibility-Eigenschaft.Diese Eigenschaft verwendet Visibility, und diese ist ein plattformabhängiges Objekt.

  6. Wählen Sie auf der Menüleiste Datei, Hinzufügen, Neues Projekt aus.Erweitern Sie unter Installiert den Knoten Visual C#, und wählen Sie dann die Projektvorlage WPF-Anwendung aus.Nennen Sie das neue Projekt Desktop, und klicken Sie dann auf die Schaltfläche OK.

  7. Öffnen Sie das Kontextmenü für den Knoten Verweise im Projekt Desktop, und wählen Sie dann Verweis hinzufügen aus.Wählen Sie unter Projektmappe die Projekte Spreadsheet und ViewModels aus.

  8. Öffnen Sie die Datei app.config für die WPF-Anwendung, und fügen Sie dann die folgenden Codezeilen hinzu.Dieser Code konfiguriert die entsprechenden bindenden Umleitungen, die angewendet werden, wenn eine Desktop-App für .NET Framework 4.5 auf eine portable .NET-Bibliothek verweist, die F# verwendet.Die portablen .NET-Bibliotheken verwenden Version 2.3.5.0 der FSharp.Core-Bibliothek, und die .NET Framework 4.5-Desktop-Apps verwenden Version 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>
    

    Jetzt müssen Sie einen Verweis auf die portable Version der F#-Kernbibliothek hinzufügen.Dieser Verweis ist immer erforderlich, wenn eine Anwendung eine portable Bibliothek nutzt, die auf eine portable F#-Bibliothek verweist.

  9. Öffnen Sie das Kontextmenü für den Knoten Verweise im Projekt Desktop, und wählen Sie dann Verweis hinzufügen aus.Wählen Sie Durchsuchen aus, und navigieren Sie dann im Ordner Programme, in dem Visual Studio installiert ist, zu Reference Assemblies\Microsoft\FSharp\3.0\Runtime\.NETPortable\FSharp.Core.dll.

  10. Fügen Sie im Projekt Desktop den Dateien App.xaml.cs und MainWindow.xaml.cs using-Direktiven für ViewModels.cs und Portable.Samples.Spreadsheet hinzu.

    using ViewModels;
    using Portable.Samples.Spreadsheet;
    
  11. Öffnen Sie die Datei MainWindow.xaml, und ändern Sie dann das title-Attribut der Window-Klasse in Spreadsheet.

  12. Kopieren Sie den Code im Grid-Element von MainPage.xaml im Silverlight-Projekt, und fügen Sie diesen Code in das Grid-Element von "MainWindow.xaml" im Projekt Desktop ein.

  13. Kopieren Sie den Ereignisbehandlungscode in MainPage.xaml.cs aus dem Silverlight-Projekt, und fügen Sie den Code in MainWindow.xaml.cs im Projekt Desktop ein.

            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. Fügen Sie dem MainWindow-Konstruktor in MainWindow.xaml.cs den Startcode für die Spreadsheet-App hinzu, und ersetzen Sie Verweise auf MainPage durch Verweise auf MainWindow.

        public MainWindow()
        {
                var spreadsheet = new Spreadsheet(5, 5);
                var spreadsheetViewModel = new SpreadsheetViewModel(spreadsheet);
    
    
                this.DataContext = spreadsheetViewModel;
                InitializeComponent();
        }
    
  15. Öffnen Sie das Kontextmenü für das Projekt Desktop, und wählen Sie dann Als Startprojekt festlegen aus.

  16. Drücken Sie die Taste F5, um die App zu erstellen, und debuggen Sie dann die App.

Nächste Schritte

Alternativ können Sie die Projekte für die App im Windows Store und die Silverlight-App ändern, damit sie die neue portable ViewModels-Bibliothek verwenden.

Weitere Informationen zu Apps im Windows Store finden Sie im Windows-Developer Center.

Siehe auch

Konzepte

Windows Store-Apps

Plattformübergreifende Entwicklung mit .NET Framework

Weitere Ressourcen

Beispiele und exemplarische Vorgehensweisen für Visual F#

Silverlight