Hast du eine Referenz dafür? Ich finde leider nichts in die Richtung auf den Microsoft-Seiten oder wir meinen nicht das Gleiche.
Damit wir uns nicht missverstehen: Meine App läuft nicht oder nur "pausiert" im Hintergrund, wenn ein Push-Update eintrifft. Wäre ja auch zwecklos, wenn meine App laufen müsste um einen ungesehen-counter auf der Startseite hoch zu setzen.
Hallo zusammen,
ich versuche gerade ein Live Tile zu erstellen, welches mir die Anzahl von ungelesenen Benachrichtigungen anzeigt. Da dies nicht durch die App beim Ausführen dieser gesteuert werden kann, muss ich dafür auf die Windows Push Notification Services (WNS) zurückgreifen.
Das Pushen an sich ist kein Problem. Das bekommen ich für Toast-Nachrichten bereits hin. Mein Problem ist nun, wie ich einen Counter auf dem Endgerät um 1 durch eine Push-Nachricht erhöhen kann.
Ich kann absolute Werte (=Texte) ohne Probleme in das Live-Tile machen, aber ich habe bisher keine Möglichkeit gefunden relative Werte zu senden (z.B. "erhöhe um 1").
Das was ich machen möchte ist im Prinzip vergleichbar mit der Anzahl an ungelesenen E-Mails in einem Live Tile. Da wissen Microsofts Server ja auch nicht, wie viele das nun wirklich sind (hoffe ich zumindest, wenn man seine Mails nicht dort hat). Trotzdem wird das Live Tile um 1 erhöht ohne dass ich die E-Mail-App geöffnet habe.
Hi ujr,
ich habe einmal eine minimale Anwendung erstellt.
Dabei ist mir zu meiner Verwunderung aufgefallen, dass das Problem nur aufzutreten scheint, wenn ich das Control via Binding in das Dock einbette.
Wenn ich das Control direct in die Form oder direkt in das Dock via XAML lege, wird Loaded aufgerufen.
Ich habe das Minimalprojekt einmal angehängt.
Nachdem ich nun einen ziemlich frustrierenden Tag damit verbracht habe dem Problem auf die Spur zu kommen habe ich folgendes festgestellt:
Wenn ich in dem Constructor von TabBase und/oder TabHuman das Event abonniere und in der Methode dazu eine Exception schmeiße, wird diese Exception im Designer angezeigt.
public TabBase()
{
this.Loaded += TabBase_Loaded;
}
void TabBase_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
throw new NotImplementedException("TabBase_Loaded");
}
Wenn ich das Projekt compiliere und starte gibt es aber keine Exception. Auch im Output-Fenster steht nichts. Wende ich das gleiche ausschließlich auf das TabHumanEuropean an, passiert nichts. Der Designer zeigt keinen Fehler mehr an, compilieren und starten geht.
Mir will einfach nicht in den Kopf, warum das Loaded-Event nicht aufgerufen wird.
Des Weiteren Funktionieren im TabHumanEuropean scheinbar alle anderen Events, nur das Loaded-Event nicht.
Wie bereits geschrieben, funktioniert das Initialized Event. Auch das Loaded-Event des eingebetteten Grids wird aufgerufen. Nur eben nicht das Loaded-Event des Controls selbst.
Auch ein "manuell" definiertes Event im Constructor wird nicht aufgerufen:
public TabHumanEuropean()
{
InitializeComponent();
this.Loaded += TabHumanEuropean_Loaded;
}
void TabHumanEuropean_Loaded(object sender, RoutedEventArgs e)
{
MessageBox.Show("Loaded by Constructor-Loaded");
}
Ein ViewModel ist kein Steuerelement, und erbt daher auch nicht von UserControl.
Ja, da hast du Recht. Das ganze ist etwas gewachsen und nicht final. Primär geht es mir um das Problem und nicht um die Struktur.
Du hast keine Ereignisse definiert
Das Loaded-Event wird doch von UserControl mitvererbt? Beim "ViewModelTabHuman" klappt das ganze ja auch.
Deine Methoden sind als
private
deklariert und daher von außen nicht zugreifbar
Ja, das ist richtig. Da das Control es selbst aufruft, funktioniert es aber. Bitte die Namensgebung ignorieren. Es ist definitiv kein ViewModel - anders als es benannt ist. Das muss ich noch korrigieren, wenn ich das grundsätzliche Problem gelöst habe.
Edit:
Ich habe im Ursprungs-Post einmal den Begriff "ViewModel" entfernt um Verwirrungen zu vermeiden und den Fokus auf das Problem und nicht das drum herum zu lenken.
Hi,
ich habe ein Problem.
Ich habe ein UserControl, dass von einem UserControl erbt, das von einem UserControl erbt, das von UserControl und INotifiyPropertyChanged erbt.
Der Reihe nach: Hier einmal die Basis, die von UserControl und INotifyPropertyChanged erbt:
namespace myapp
{
public class TabBase : UserControl, INotifyPropertyChanged
{
public TabBase()
{
}
private string _Title = "Unnamed";
public string Title
{
get { return _Title; }
set
{
if (_Title == value) return;
_Title = value;
RaisePropertyChanged("Title");
}
}
#region PropertyChanged
protected virtual void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
}
Hier die Klasse, die davon erbt:
namespace myapp
{
public class TabHuman : TabBase
{
public string Firstname { get; set; }
public string Lastname { get; set; }
}
}
Und hier das UserControl, welches das "Endprodukt" darstellt:
namespace myapp.Tabs.TabHumanEuropean
{
public partial class TabHumanEuropean
{
public TabHumanEuropean()
{
InitializeComponent();
}
private void TabHuman_Loaded(object sender, RoutedEventArgs e)
{
MessageBox.Show("Loaded");
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(this.IsLoaded.ToString());
}
}
}
und der XAML-Code:
<tabs:TabHuman x:Class="myapp..Tabs.TabHumanEuropean.TabHumanEuropean"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:="clr-namespace:myapp.tabs"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Loaded="TabHuman_Loaded"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
>
<Grid Background="Red">
<Button Content="Show" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
</tabs:TabHuman>
Im letzten der drei Klassen wird nun aber das "Loaded"-Event nicht ausgelöst und die Eigenschaft "IsLoaded" bleibt auf false. Im Gegensatz dazu wird das Initialized-Event (nicht im Code) aber aufgerufen.
Wenn ich jetzt nicht von TabHuman erben lasse, sondern von TabBase funktioniert das Loaded-Event.
Ich kann mir das nicht so richtig erklären. Kann mir hier jemand weiterhelfen? Was habe ich für Möglichkeiten das Problem zu lösen?
Hi Coffeebean,
vielen Dank für deine Antwort. Das hat mir sehr weitergeholfen!
Ob ich wirklich für jeden Click eine eigene Klasse mache oder ob ich das in der Praxis dann ggf. doch anders mache, wird sich zeigen. Erstmal aber möchte ich es mit eigenen Klassen machen um zu wissen wie es dann in der Theorie und Praxis mal alles funktionieren würde.
Hi,
ich möchte gerne ein Programm schreiben, welches MVVM-conform ist. Dazu gehört auch, soviel ich bisher verstanden habe, nicht die "klassischen" z.B. Button_Click-Events eines Controls zu benutzen, sondern dies über CommandBindings umzusetzen.
Dazu habe ich bisher folgendes gemacht:
XAML:
<RibbonWindow
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MvvmTest.GUI_v2.ViewModels"
xmlns:cmds="clr-namespace:MvvmTest.GUI_v2.ViewModels.Commands"
x:Class="MvvmTest.GUI.MainWindow"
Title="MvvmTest"
Height="600"
Width="800"
WindowState="Normal"
WindowStartupLocation="CenterScreen"
>
<RibbonWindow.DataContext>
<local:ViewModelMain />
</RibbonWindow.DataContext>
<RibbonWindow.CommandBindings>
<!-- Geht nicht -->
<CommandBinding Command="cmds:Login.CmdLogin" CanExecute="Login_CanExecute" Executed="Login_Executed" />
<!-- Geht auch nicht -->
<CommandBinding Command="cmds:Login.CmdLogin" CanExecute="cmds:Login.Login_CanExecute" Executed="cmds:Login.Login_Executed" />
</RibbonWindow.CommandBindings>
<Grid>
<Button Content="Login" Command="cmds:Login.CmdLogin" HorizontalAlignment="Left" VerticalAlignment="Top" IsDefault="True" Width="200" Margin="0,0,0,5"/>
</Grid>
</RibbonWindow>
Mein ViewModelMain (NameSpace: MvvmTest.GUI.ViewModels) ist zur Zeit noch leer.
Für die Commands möchte ich gerne im NameSpace MvvmTest.GUI.ViewModels.Commands jeweils eine Klasse erstellen, in denen dann die gewünschten Aktionen durchgeführt werden sollen.
Eine so eine Klasse sieht z.B. so aus:
namespace MvvmTest.GUI_v2.ViewModels.Commands
{
public class Login
{
public static RoutedUICommand CmdLogin = new RoutedUICommand("Login", "Login", typeof(Login));
public void Login_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
//e.Handled = true;
}
public void Login_Executed(object sender, ExecutedRoutedEventArgs e)
{
Console.Beep();
}
}
}
Mein Problem ist nun:
wie bekomme ich dem CommandBinding Beigebracht, dass er aus der Klasse Login das CanExecute und Executed aufrufen soll und nicht aus der CodeBehind-Datei? Im XAML Code oben habe ich bereits zwei Möglichkeiten ausprobiert, welche mir logisch erschienen, aber beide nicht funktionieren.
Bei der ersten Variante gibt es den Fehler> Fehlermeldung:
'MvvmTest.GUI.MainWindow' does not contain a definition for 'Login_Executed' and no extension method 'Login_Executed' accepting a first argument of type 'MvvmTest.GUI.MainWindow' could be found (are you missing a using directive or an assembly reference?)
Hier sucht er in der Code-Behind-Datei nach den Methoden.
Bei der zweiten Variante gibt es den Fehler:> Fehlermeldung:
CanExecute="cmds:Login.Login_CanExecute" is not valid. 'cmds:Login.Login_CanExecute' is not a valid event handler method name. Only instance methods on the generated or code-behind class are valid.
Beides kompiliert nicht.
Des weiteren hatte ich auch schon versucht die Login-Klasse sowie die (Can)Execute-Methoden static zu machen, aber auch das hat in der Verzweiflung nichts am Fehler und den Meldungen geändert.
Ich bin ein wenig ratlos und finde auch über den Freund mit den 6 Buchstaben keine Lösung, die mir im Ansatz weiterhilft. In die CodeBehind-Datei möchte ich eigentlich nichts schreiben.
Hi,
Ich benutze für meine Projekte Axialis Icon Workshop (http://www.axialis.com/iconworkshop/). Kostet einmalig etwas Geld und man hat dann einige hundert Icons auf dessen Grundlage man in deren Designer die Icons modifizieren, kombinieren oder wie auch immer verändern kann.
Kann ich nur empfehlen. Ist einfach und unkompliziert.
Hi Mammut,
soweit ich weiß, musst du noch ein PropertyChanged senden.
Dazu musst du zunächst dein Window oder Usercontrol von INotifiyPropertyChanged ableiten.
Dann musst du ein Event "PropertyChangedEventHandler" erstellen.
public event PropertyChangedEventHandler PropertyChanged;
Nachdem dann SelectedKunde und die Liste geändert wurden, rufst du PropertyChanged auf um dem Control mitzuteilen, dass es die Bindings bitte aktualisieren soll.
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("ListKunden"));
PropertyChanged(this, new PropertyChangedEventArgs("SelectedKunde"));
}