Laden...

Zugriff auf Controls aus XAML-Code

Erstellt von TimFranke vor 5 Jahren Letzter Beitrag vor 5 Jahren 1.979 Views
T
TimFranke Themenstarter:in
15 Beiträge seit 2014
vor 5 Jahren
Zugriff auf Controls aus XAML-Code

Hallo,

im Selbststudium offenbaren sich gerade Verständnislücken hinsichtlich des
Zugriffs auf Controls, die ich in einem Xamarin-Projekt im XAML-Code definiert habe.

Konkret habe ich dort eine Progressbar erzeugt.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
             x:Class="MediaSample.MediaPage"
             xmlns:local="crl-namespace:MediaSample"
             NavigationPage.HasNavigationBar="False"
bla bla
bla bla
<ProgressBar x:Name="MainProgressBar"  HeightRequest="0.5" MinimumWidthRequest="100"  Grid.Column="0" Grid.Row="1" />
bla
bla

In der Code-behind Datei kann ich Eigenschaften der Progressbar über ihren Namen ansprechen
und verändern.

In meinem Projekt habe ich noch eine weitere Klasse erzeugt, in der ich u.a. den
Wert der Progressbar setzten möchte. Allerdings gibt VisualStudio eine Fehlermeldung:
The name "MainProgressBar" does not exist in the current context.

namespace MediaSample
{
    public static class myclass
    {
      public static void run()
      {
       bla bla
       MainProgressBar.Progress = 1;
      }
    }

}

Mir scheint, dass ich noch etwas grundsätzlich an der Organisationslogik nicht verstanden habe.
Kann jemand sagen, wie ich in meiner Klasse Zugriff auf die Progressbar bekommen kann?

Gruss,
Tim

T
156 Beiträge seit 2010
vor 5 Jahren

Hi,

also in der CodeBehind, die der Designer anlegt, gibt es dann auch Designercode, der die ganzen Controls instanziiert und initilalisiert.
Also Instanzen der Controls erzeugt, dem außenliegenden Control als Children hinzufügt und alle Eigenschaften setzt, die Du im Designer zusammengeklickt hast.

Die ganzen Controls sind Instanzen, von daher kommst Du da mit einer static class, die irgendwo herumschwirrt, gar nicht ran!

Aber zu großen Glück sind ja die generierten Klassen partial
So kannst Du die Klasse dann ganz einfach erweitern:


public partial class Form1
{
   public void Run()
   {
       MainProgressBar.Progress = 1;
   }
}

T
TimFranke Themenstarter:in
15 Beiträge seit 2014
vor 5 Jahren

Hi,

ich bin mir nicht sicher, ob ich Deine Antwort in Gänze verstanden habe.
Deshalb habe ich nochmal ein Minimalbeispiel erstellt, dass mein Problem verdeutlicht.
Die Methode "start" des Klasse "myClass" kennt das Label "labeltest" nicht ...

XAML:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:test01"
             x:Class="test01.MainPage">

    <StackLayout>
        <!-- Place new controls here -->
        <Label x:Name="labeltest" Text="Label vor dem Click" 
           HorizontalOptions="Center"
           VerticalOptions="CenterAndExpand" />

        <Button x:Name="btn01" Clicked="btn01_Clicked" Text="Click"/>
    </StackLayout>
</ContentPage>

Code-behind:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace test01
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void btn01_Clicked(object sender, EventArgs e)
        {
            myClass.start();
        }
    }
}

eigene Klasse:

using System;
using System.Collections.Generic;
using System.Text;

namespace test01
{
    public partial class myClass
    {
        public static void start()
        {
            Console.WriteLine("Kontrolle");
            labeltest.Text = "Label nach dem Click";
        }
    }
}
4.939 Beiträge seit 2008
vor 5 Jahren

Warum willst du das denn überhaupt in eine eigene Klasse auslagern?

Du kannst doch direkt innerhalb der MainPage-Klasse darauf zugreifen:


private void btn01_Clicked(object sender, EventArgs e)
{
    labeltest.Text = "Label nach dem Click";
}

Wenn du eine eigenständige Logik-Klasse hast, dann sollte diese nicht direkt auf die UI zugreifen, s.a. [FAQ] Kommunikation von 2 Forms oder meinen eigenen Artikel dazu Kommunikation von 2 Forms.

T
156 Beiträge seit 2010
vor 5 Jahren

@Th69:
Gut, das ist natürlich die Frage....

@TimFranke:
Also wenn Du die partielle Klasse, die der Generator erstellt erweitern willst, dann muss Deine Klasse ebenfalls partial sein, genauso heißen und auch im gleichen Namespace sein.

Also so:


namespace test01
{
    public partial class MainPage
    {
        public static void Start()
        {
            Console.WriteLine("Kontrolle");
            labeltest.Text = "Label nach dem Click";
        }
    }
}

lG, Marko

T
TimFranke Themenstarter:in
15 Beiträge seit 2014
vor 5 Jahren

@Th69:

In meiner eigenen Klasse sollen Berechnungen ablaufen.
Über deren Fortschritt soll der Nutzer über sich ändernde Labelinhalte
informiert werden. Deshalb dachte ich mir, aus meiner Klasse heraus,
Labeltexte zu ändern.

@trashkid2000:
Wenn ich mein Beispiel nach Deiner Vorgabe anpasse,
erscheint die Fehlermeldung bei "labeltest"
An object reference is requiered for the non-static field, method, or property "MainPage.labeltest".

4.939 Beiträge seit 2008
vor 5 Jahren

Das static ist zu viel.
Aber durch das partial ist das nicht eine andere Klasse, sondern eben nur Code, der in einer anderen Datei steht.

Und genau für Rückmeldungen an UI-Klassen gibt es die Ereignisse (events), welches in beiden Artikeln erklärt wird - s.a. [FAQ] Eigenen Event definieren / Information zu Events (Ereignis/Ereignisse).

P
441 Beiträge seit 2014
vor 5 Jahren

Nichts für ungut, aber das was ihr mit partial macht ist nur ein verschlimmbessern des Codes.

Partial sorgt ja im Endeffekt nur dafür, dass der Compiler "den Code vor dem Kompilieren zusammenkopiert".
Im Sinne von OOP wäre hier ein Entwurfsmuster anzuwenden, dass dieses Problem löst und eine saubere Trennung erzeugt. Für WPF wäre das MVVM, mit Xamarin habe ich selber noch nichts gemacht, aber XAML weist an sich schon auf MVVM hin. Entsprechend sollte es ein ViewModel geben, welches den Fortschritt als Property bereitstellt und ein Command im ViewModel zum starten der Hintergrundaktion.

Code Behind Spielereien werden sehr schnell zu komplex (und nichts anderes macht partial ja) um sie zu handhaben.