Laden...

Forenbeiträge von N0ACE Ingesamt 5 Beiträge

21.07.2014 - 08:49 Uhr

Hi und danke für den Tipp!

Wenn ich den DataContext in der CodeBehind-Datei definiere, funktioniert dies leider noch immer nicht; das Verhalten ist vorher.
Aber mir ist da noch was anderes aufgefallen: Wenn ich in meinem CustomControll das Binding der Text-Property des TextBlocks nicht näher definiere (also keinen Path angebe), so wird in meinem TestProjekt gebunden; zwar wird nur Klassenpfad dargestellt (weil er ja nicht weiß, welches Element er binden soll), aber er bindet sowohl bei der direkten Zuweisung (<H:BaseHeadline Title="Test"/>) als auch beim Binding (<H:BaseHeadline Title={Binding TestText}/>)

Des Weiteren habe ich noch folgendes versucht: Das CustomControl hat einen Namen bekommen (x:Name="Base"):


<UserControl x:Class="TEST_Headlines.BaseHeadline"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:local="clr-namespace:TEST_Headlines"
             mc:Ignorable="d"
             d:DesignHeight="50" d:DesignWidth="400"
             x:Name="Base"
             DataContext="{Binding RelativeSource={RelativeSource Self}}">
    
    <Grid>
        <Border/>
        <TextBlock Text="{Binding Path=Title, ElementName=Base}"/>
    </Grid>
</UserControl>

Hier ist jetzt das Interessante, das in meinem Testprojekt zwar beides Mal mein CustomControl dargestellt wird, aber beim Setzen des Titles via Binding (<H:BaseHeadline Title={Binding TestText}/>) wird kein Text dargestellt (aber ein "leeres" Element; es collapsed nicht).

Für weitere Hilfe wäre ich sehr dankbar!

18.07.2014 - 12:53 Uhr

Hallo zusammen,

Ich habe ein CustomControl erstellt, welches im Prinzip ein einfacher TextBlock ist, dessen Inhalt ich via Bindung füttern will. Der XAML-Code sieht folgendermaßen aus:


<UserControl x:Class="TEST_Headlines.BaseHeadline"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             d:DesignHeight="50" d:DesignWidth="400"
             DataContext="{Binding RelativeSource={RelativeSource Self}}">


    <Grid Background="Red">
        <Border/>
        <TextBlock Text="{Binding Title}"/>
    </Grid>
</UserControl>

Die CodeBehind-Datei enthält folgenden Code:


// using ...

namespace TEST_Headlines
{
    public partial class BaseHeadline : UserControl
    {
        public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
            "Title",
            typeof(string),
            typeof(BaseHeadline),
            null
        );
        
        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        public BaseHeadline()
        {
            InitializeComponent();
        }
    }
}

Dieses CustomControll erstelle ich und füge einen Verweis auf die DLL in ein neues Projekt. Das neue Projekt, welches dieses CustomControl nutzen soll, sieht so aus:


<UserControl x:Class="TEST_Libs_Testing_Components.MainPage"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:local="clr-namespace:TEST_Libs_Testing_Components"
             xmlns:H="clr-namespace:TEST_Headlines;assembly=TEST_Headlines"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="400">
    
    <UserControl.DataContext>
        <local:Dummy/>
    </UserControl.DataContext>
    
    <Grid x:Name="LayoutRoot" Background="White">
        <StackPanel>
            <H:BaseHeadline Title="funktioniert"/>
            <H:BaseHeadline Title="{Binding TestText}"/>
            <TextBlock Text="{Binding TestText}"/>
        </StackPanel>
    </Grid>
</UserControl>

Die dazugehörige CodeBehind-Datei enthält keinen weiteren Code. Es wurde aber eine Dummy-Klasse dem Projekt hinzugefügt, welche zu Testzwecken Daten fürs Binding enthält:


// using ...

namespace TEST_Libs_Testing_Components
{
    public class Dummy : INotifyPropertyChanged
    {
        private String _TestText;
        public String TestText
        {
            get
            {
                return this._TestText;
            }
            private set
            {
                if (this._TestText != value)
                {
                    this._TestText = value;
                    OnPropertyChanged("TestText");
                }
            }
        }

        public Dummy()
        {
            this.TestText = "Hello World";
        }

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

        public event PropertyChangedEventHandler PropertyChanged;
    }
}

Das Ergebnis ist, dass das Binding für mein CustomControl nicht funktioniert. Der TextBlock zeigt "Hello World", mein CustomControl bleibt leer. Wenn ich das Title-Attribut aber direkt mit einem Wert versehe und nicht das Binding nutze, wird mir der Text korrekt dargestellt....

Was fehlt meiner Klasse BaseHeadline, damit auch hier der Text entsprechend dargestellt wird?

Vielen Dank für Eure Hilfe!!!

11.07.2014 - 11:33 Uhr

Hallo abermals!

Ich wollte noch mal auf mein vorheriges Posting hinweisen, insbesondere auf die Fragestellung, ob ich mit den Ergebnis (Objekte) einer context.Load()-Methode immer im Callback arbeite. Einerseits leuchtet es ein, da durch den asynchronen Aufruf nicht definiert ist, wann die Antwort des Servers zur Verfügung steht. Andererseits frage ich mich, ob meine Lösung, wie oben beschrieben, etwaige Nachteile aufweist, bzw. was geändert werden soll/muss/kann.

Vielen Dank für die Hilfe!!

10.07.2014 - 09:30 Uhr

Hi Coffeebean und vielen Dank für die Antwort!

Vorab: Ich habe mich leider in meinem ersten Post vertippt: Die Methode lautet GetUserByUsernameQuery(string username) (Was natürlich egal ist, wie die Methode heisst; was ich eigentlich damit sagen möchte ist, dass diese Methode in PowerusersService.cs im Web-Projekt definiert ist)

Ich habe inzwischen noch ein wenig herumprobiert und das Problem war wohl, dass ich meinen loadedUser zu früh genutzt habe; nicht im Callback.

Ich habe (testhalber) ein neues, leeres Projekt erstellt:1. Dem Web-Projekt wurde ein "Daten/ADO.NET Entity Data Model"-Element hinzugefügt (wurde aus bestehender DB generiert und die entsprechenden 4 Tabellen selektiert)

  1. Im Web-Projekt wurde die Codegenerierungsstrategie des PowerusersModel.edmx auf "Standard" gesetzt und die beiden *.tt-Dateien gelöscht
  2. Dem Web-Projekt wurde eine "Internet/Domänendienstklasse" hinzugefügt (mit allen 4 Tabellen / 3 davon mit dem Recht, zu editieren; User nur lesend)
  3. MainPage.xaml enthält nur einen Button zum Laden

Mein Code sieht momentan folgendermaßen aus:


// Web-Projekt - PowerusersService.cs (DomainServiceClass)
//               wurde um folgende Methode erweitert
public User GetUserByUsername(string userName)
{
    return this.ObjectContext.Users
        .Where(u => u.userName == userName)
        .FirstOrDefault();
}


// Code-Projekt - MainPage.xaml.cs (CodeBehind)
// private member der MainPage-Klasse, sodass ich von jeder Methode aus darauf zugreifen kann
private PoweruserContext _ctx;

public MainPage()
{
    InitializeComponent();
    _ctx = new PoweruserContext();
}


private void LoadAllUsers_Click(object sender, RoutedEventArgs e)
{
    LoadOperation loadOp = _ctx.Load(_ctx.GetUsersQuery());
    loadOp.Completed += loadOp_Completed;
}

void loadOp_Completed(object sender, EventArgs e)
{
    LoadOperation loadOp = sender as LoadOperation;
    if (loadOp.HasError)
    {
        MessageBox.Show("LoadOp Error: " + loadOp.Error.Message);
        loadOp.MarkErrorAsHandled();
    }
    else
    {
        foreach (User u in _ctx.Users)
        {
            MessageBox.Show(u.firstName + " " + u.lastName + " (" + u.userName + ")");
        }
    }
}


private void LoadSingleUser_Click(object sender, RoutedEventArgs e)
{
    LoadOperation loadOp = _ctx.Load(_ctx.GetUserByUsernameQuery("johndoe"));
    loadOp.Completed +=loadOp_SingleCompleted;
}

void loadOp_SingleCompleted(object sender, EventArgs e)
{
    LoadOperation loadOp = sender as LoadOperation;
    if (loadOp.HasError)
    {
        MessageBox.Show("LoadOp Error: " + loadOp.Error.Message);
        loadOp.MarkErrorAsHandled();
    }
    else
    {
        User u = _ctx.Users.FirstOrDefault();
        MessageBox.Show(u.firstName + " " + u.lastName + " (" + u.userName + ")");
    }
}

Dies funktioniert auch; alle User werden geladen und auch das Laden des einzelnen Users funktioniert!

Nur, ist dies sauber? "Wird das so gemacht"? Oder gibt es da schönere Möglichkeiten?

Ich verstehe das bisher so, dass ich mittels der Load()-Methode meines PowerusersContext die Menge an Inhalten (= die Einträge/Objekte als Eigenschaften; bspw. _ctx.Users, _ctx.Groups, _ctx.States und _ctx.PowerUsers) des PowerusersContextes manipuliere: Zu Anfang ist _ctx.Users leer, dann rufe ich die GetUsersQuery()-Methode auf, danach ist _ctx.Users gefüllt mit allen Benutzern. Rufe ich im Anschluss die GetUserByUsernameQuery()-Methode, enthält _ctx.Users nur noch das gefundene Objekt.

Wieso schreibst du:

  
EntityQuery<User> query = ctx.GetUserByUsername("istVorhanden");  
  

und nicht

  
User user = ctx.GetUserByUsername("istVorhanden");  
  

?

Wenn ich letzteres schreibe, meckert Visual Studio:

Fehlermeldung:
Eine implizite Konvertierung vom Typ "System.ServiceModel.DomainServices.Client.EntityQuery<PROJECT_Name.Web.User>" in "PROJECT_Name.Web.User" ist nicht möglich

Vielen Dank für die Hilfe!!!!

08.07.2014 - 17:02 Uhr

Hallo zusammen,

ich habe folgende Situation und sehe bisher leider kein Licht am Ende des Tunnels: Es wird eine Silverlight-Anwendung programmiert, welche eine recht einfache Oberfläche zum Hinzufügen, manipulieren und löschen von Datensätzen darstellen soll.

Die zu Grunde liegende DB sieht (vereinfacht) folgendermaßen aus:

Groups: id, name
States: id, name
Users: id, username
PowerUsers: id, groupId, stateId, userId

D.h., ein PowerUser hat sowohl eine Gruppe, als auch einen Status.
Auf die Tabelle Users kann ich nur lesend zugreifen, daher der ForeignKey für den User.
=> PowerUser hat also drei ForeignKeys

CRUD-Operationen für die Groups und States habe ich erfolgreich implementiert bekommen (via WCF-RIA-Service), jedoch bereiten mir die PowerUsers Kopfzerbrechen. Die Create-Ansicht für einen PowerUser sieht in etwa so aus:

Gruppe: [ComboBox] (Stellt auch alle Gruppen dar)
Status: [ComboBox] (Stellt auch alle Status' dar)
username: [TextBox] (freies Textfeld...)

sobald ein Username eingetragen wird, möchte ich das entsprechende User-Object aus der Tabelle Users erhalten, sodass ich diesen entsprechend hinzufügen kann.

Leider habe ich keine Ahnung, wie ich an dieses User-Object mit dem entsprechenden Usernamen herankomme.

Folgendes habe ich (u.a.) versucht:

// PowerusersService.cs - erweitert um folgende Methode:
public User GetUserByUsername(string username)
{
    return this.ObjectContext.Users
        .Where(u => u.username == username)
        .First();
}
// PoweruserAdd.xaml - im Save_Click-Event:
PowerusersContext ctx = new PowerusersContext();
EntityQuery<User> query = ctx.GetUserByUsername("istVorhanden");
LoadOperation<User> loadOp = ctx.Load(query);

User loadedUser = loadOp.Entities.First();
// loadedUser ist immer NULL, Nachname ist definitiv in DB vorhanden

Für etwaige Hilfe, wie ich dieses "fremd-geladene" User-Object dem PowerUser zuordnen kann, wäre ich sehr dankbar!

Mit freundlichen Grüßen!