@Abt: Ja, das ist klar. Aber wie setzt man das im Fall einer CollectionView um? VirtualScrollView gibt es bei Maui scheinbar nicht oder ich hab da zumindest noch nichts gefunden.
Ich hab jetzt testweise übrigens das Projekt aus dem oben genannten Ticket genommen und ausprobiert. Das läuft zwar nicht flüssig, aber man kann es immerhin bedienen, was bei meinem Projekt schon nicht mehr geht. Also minimal angepasst und statt der Beispielbilder hab ich die Bilder aus meinen Quellen genommen und man kann es immer noch bedienen.
Jetzt hab ich den Verdacht, dass es irgendwie mit dem Binding zusammenhängt. Aber das ist nur ein Verdacht. Ich werde jetzt auf jeden Fall mal das Fremdprojekt step für step so erweitern, dass es meinem Projekt entspricht. Irgendwo muss der Knackpunkt ja sein, der das ganze unbedienbar macht
@Th69: Danke für die Antwort...
Guter Ansatz, dass ich das mal mit weniger Bildern probieren 😃. Ja... Bis 50 Bilder läuft es noch flüssig. Ab 60 wird es ein bisschen hakelig und ab 80 ist es nicht mehr bedienbar.
Die Bilder liegen direkt als 150x150 JPG vor. Werden also nicht mehr codeseitig skaliert. Das hab ich schonals ersten Ansatz vorgearbeitet, weil ich dachte, dass die Skalierungsarbeit evtl. Probleme machen könnte. Hat aber nichts geändert.
Hallo zusammen,
ich versuche aktuell eine Anwendung, die ich mal mit Angular und Ionic entwickelt habe, mit Maui neu zu programmieren. Es geht dabei um eiune Verwaltung von Hörbüchern. Ziel ist, dass ich die gleiche Anwendung (Codebasis) sowohl unter Android als auch unter Windows verwenden kann.
Eine Ansicht davon ist eine Liste mit allen Covern der registrierten Hörbüchern. Die Cover werden in einem CollectionView angezeigt. Unter Windows ist das kein Problem. Aber unter Android ist es unmöglich in der Liste zu scrollen.
Die Cover sind dabei als Bild-Datein auf dem jeweiligen Gerät vorhanden. Im Image verwende ich einen FileImageSource mit Bindung auf den jeweiligen Pfad zur Bilddatei.
Hier der Xaml-Code
<CollectionView ItemsSource="{Binding Audiobooks}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Audiobook">
<VerticalStackLayout Padding="15">
<Image WidthRequest="150" HeightRequest="150">
<Image.Source>
<FileImageSource File="{Binding ImagePath}" />
</Image.Source>
</Image>
</VerticalStackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="{Binding Columns}" />
</CollectionView.ItemsLayout>
</CollectionView>
Wie gesagt: Unter Windows keine Probleme. Es handelt sich hier um ca. 300 Bilder alle in der Größe 150x150 Pixel.
Unter Android bewegt sich der Scrollview 10 10 Sekunden vielleicht um einen Pixel. Also absolut nicht bedienbar.
Im Logcat hab ich immer Meldungen in dieser Art:
[Choreographer] Skipped 218 frames! The application may be doing too much work on its main thread.
[EGL_emulation] app_time_stats: avg=1919.20ms min=165.86ms max=3672.54ms count=2
[OpenGLRenderer] Davey! duration=3854ms; Flags=0, FrameTimelineVsyncId=126296, IntendedVsync=1178942486484, Vsync=1179109153144, InputEventId=0, HandleInputStart=1179117296448, AnimationStart=1179117309748, PerformTraversalsStart=1179117329048, DrawStart=1182617312148, FrameDeadline=1179125819810, FrameInterval=1179116961548, FrameStartTime=16666666, SyncQueued=1182636644548, SyncStart=1182642993148, IssueDrawCommandsStart=1182768628148, SwapBuffers=1182770803848, FrameCompleted=1182803662348, DequeueBufferDuration=13300, QueueBufferDuration=254500, GpuCompleted=1182803662348, SwapBuffersCompleted=1182771395948, DisplayPresentTime=0, CommandSubmissionCompleted=1182770803848,
[OpenGLRenderer] Davey! duration=3807ms; Flags=0, FrameTimelineVsyncId=126311, IntendedVsync=1179125819810, Vsync=1182759152998, InputEventId=0, HandleInputStart=1182769331548, AnimationStart=1182769392948, PerformTraversalsStart=1182769805048, DrawStart=1182770136148, FrameDeadline=1182825819662, FrameInterval=1182768873148, FrameStartTime=16666666, SyncQueued=1182770324948, SyncStart=1182779469248, IssueDrawCommandsStart=1182926049948, SwapBuffers=1182927572448, FrameCompleted=1182942847248, DequeueBufferDuration=16100, QueueBufferDuration=185900, GpuCompleted=1182942847248, SwapBuffersCompleted=1182927938848, DisplayPresentTime=0, CommandSubmissionCompleted=1182927572448,
[audiobooks.maui] Explicit concurrent copying GC freed 3501(160KB) AllocSpace objects, 0(0B) LOS objects, 49% free, 10MB/20MB, paused 236us,36us total 14.939ms
Für mich sieht es so aus, als ob das Rendern im MainThread so extrem viel Performance braucht und daher die UI blockiert. Gibt es eine Möglichkeit, das Rendern irgendwie in einen Thread zu verschieben? Bzw. gibt es eine andere, performantere Anzeige-Möglichkeit unter Android?
Ich bin für jeden Tipp dankbar 😉
Hallo zusammen,
ich wollte mir gerade das Auslesen von Attributen über die Methode GetCustomAttributes genauer ansehen und sehen, wie der Parameter inherit richtig verwendet wird, Dabei bin ich über folgende Fälle gestolpert, die ich eigentlich anders erwartet hätte:
[MyAttribute("BaseClass")]
public class BaseClass { }
[MyAttribute("ChildClass")]
public class ChildClass : BaseClass { }
wenn ich hier über die ChildClass die Attribute abrufe wird mit Parameter inherit = true nur das Attribut gefunden, dass bei der ChildClass verwendet wurde. Das Attribut über BaseClass wird nicht gefunden.
typeof(ChildClass).GetCustomAttributes(true);
Ich hätte hier eigentlich erwartet, dass beide Attribute gefunden werden. Verstehe ich das falsch? Gibt es vielleicht auch eine Möglichkeit, dass man beide Attribute findet?
Der zweite Fall hat mich dann richtig stutzig gemacht:
[MyAttribute("IBaseInterface")]
public interface IBaseInterface { }
public class ChildClass : IBaseInterface { }
wenn ich hier auf ChildClass die Attribute suche, wird gar nichts gefunden. Da hätte ich erwartet dass das Attribute von IBaseInterface gefunden wird.
typeof(ChildClass).GetCustomAttributes(true);
Wenn ich statt dem Interface eine Basisklasse verwende, wird das Attribut entsprechend gefunden. Von daher hätte ich das gleiche Verhalten auch erwartet, wenn ich stattdessen ein Interface verwende.
Warum schreibe ich das hier? In meinen Augen sind das zwei Fälle, über die man gerne mal stolpern könnte. Daher würde ich gerne versuchen, die Hintergründe zu verstehen, damit ich mir das leichter merken kann. Vielleicht hat da jemand ein paar Informationen dazu.
Da muss man ein bisschen "Bugusing" betreiben 😃
Man kann statt einem Int64 auch einen String in qword reinschreiben und damit funktioniert es dann
[Registry]
Root: "HKLM64"; Subkey: "SOFTWARE\Name\{#MyAppName}"; ValueType: qword; ValueName: "TStamp"; ValueData: "{code:GetTimestamp}"; Flags: createvalueifdoesntexist
[Code]//Unix Timestamp
function GetUnixTimestamp(ATimerPtr: Int64): Int64;
external 'time@msvcrt.dll cdecl';
function GetTimeStamp: string;
var
value:int64;
begin
value := GetUnixTimeStamp(0);
Result := IntToStr(value);
end;
Was ich mich aber eher frage... Gibt es nicht auch in Inno eine Funktion für den UnixTimestamp?
Hallo zusammen,
wenn man in einem Programmnamen das Wort "Install" verwendet, geht Windows scheinbar automatisch davon aus, dass es sich um ein Installationsprogramm handelt. Unter gewissen Umständen (ich glaub, wenn sich die Installationsdatenbank nicht verändert), wird dann am Ende gefragt, ob das Programm richtig installiert wurde.
Kann man diese Rückfrage von Windows irgendwie umgehen? Eine bestimmte Signatur ins Programm einfügen oder was weiß ich. Vielleicht hat da jemand eine Idee.
ich weiß: Die einfachste Möglichkeit ist, dass man das Programm einfach umbenennt, aber vielleicht gibt es ja was anderes nettes.
Vielen Dank schon mal
Kürzeste Antwort: .net core.
(zB
> )
Aber da steht auch drin, dass man von project.json auf msbuild wechseln will.
The .NET Core tooling is going to move from project.json to MSBuild-based projects in a future release. The recommendation is to still use project.json files for new .NET Core projects since there will be a path to convert your project to MSBuild when the tooling is released.
okay, bis auf den Bezug auf den Namen (javascript object notation, hat nichts mit Java zu tun. Und json selbst ist halt inzwischen DAS universelle serialisierte Datenaustauschformat)
Ich wollte damit auch nicht sagen, dass es was mit java zu tun (Ok, ich hab ein Leerzeichen zuviel drin). Aber json kommt definitiv von Javascript.
Für den Datenaustausch ist es auch vollkommen in Ordnung. Da bringt json natürlich viele Vorteile mit sich, weil man relativ problemlos zwischen verschiedenen Architekturen austauschen kann.
Aber eine Konfigurationsdatei hat meiner Meinung nach nicht viel mit Datenaustausch zu tun.
Also warum json in .NET Entwicklung empfohlen wird, versteh ich ehrlich gesagt nicht. Allein schon vom Namen her (Java Script Object Notation) ist eigentlich schon klar, wo json hingehört.
Json finde ich als Konfigurations-Format absolut untauglich, da es meiner Meinung nach (und auch nach der Meinung meiner meisten Kunden) schlecht lesbar ist und daher auch schwierig zu bearbeiten ist.
XML ist in .NET viel leichter zu verarbeiten. Es gibt nativ alle Methoden dafür, die man benötigt und man braucht keine zusätzliche Komponente. Klar ist XML ziemlich aufgebläht, aber wir reden hier nur von einer Konfigurations-Datei. Da spielen meiner Meinung nach ein paar Byte mehr oder weniger keine Rolle.
Aber auch bei XML hatte ich schon Probleme mit Kunden, weil sie damit nicht umgehen können.
Für den absoluten DAU ist meistens wirklich eine INI-datei mit entsprechenden Kommentaren am leichtesten zu verstehen und kann vom Kunden auch am ehesten bearbeitet werden. Ein kleiner Parser dafür ist auch mit einfachen Mitteln (Regex und Co) schnell erstellt und gegebenfalls gibt es dafür auch einige gute Komponenten, die das Leben damit gewaltig vereinfachen.
Wenn jetzt jemand behauptet, dass eine Config-Datei ja auch nicht für den Kunden lesbar sein muss, weil man dafür in der Regel eine Konfigurations-Oberfläche bereitstellt, dem geb ich natürlich recht. Aber dann brauch ich auch kein Textformat um die Konfiguration zu speichern, sondern dann speicher ich die Konfiguration binär als Object-Dump und gut ist.
Im Grunde kommt es immer auch die Anforderung an, die der Kunde stellt.
Meine persönliche Empfehlung ist XML. Ich habe eine Objekt (static oder singleton), in dem alle bekannten Properties enthalten sind und im Konstruktor dieses Objekts wird die Konfigurations-Datei gelesen und per Linq2Xml verarbeitet und die einzelnen Properties gefüllt. Fertig ist die Wurst. Wenn man noch die Möglichkeit zur Änderung der Konfiguration einbaut, gibt es dann eben noch eine SaveToXml Methode, die die Properties dann eben wieder in ein Xml packt und das Ganze wegschreibt.
Alternativ kann man auch noch per Serialisierung das Ganze ein bisschen vereinfachen.
Vielleicht ein bisschen ungünstig ausgedrückt...
Ich möchte eine Editorkomponente erstellen, wie es bei ToolStrip oder MenuStrip auch der Fall ist. Das heißt, dass ich im Designer die Möglichkeit bieten möchte, dass man direkt Menüpunkte hinzufügt und bearbeitet.
Beim ToolStrip zum beispiel wird ja im Designer eine Schaltfläche angezeigt, über die man Komponenten zum ToolStrip hinzufügen kann und dann auch entsprechend die Events setzen kann.
Mir fehlt da allerdings vollkommen der Ansatz, wie man so etwas macht.
Hallo zusammen,
ich möchte gerade eine eigene Menükomponente erstellen. Diese beinhaltet Items auf nur zwei Ebenen. Zum einen eine Liste von "HeaderItems" und die beinhalten jeweils eine Liste von "NavItems"
Die beiden Klassen "HeaderItem" und "NavItem" leite ich jeweils von System.ComponentModel.Component ab.
(Code ganz stark vereinfacht)
public class HeaderItem: Component
{
public HeaderItem()
{
Items = new List<NavItem>();
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public List<NavItem> Items { get; set; }
...
}
public class NavItem: Component
{
public string Text { get; set; }
public event EventHandler Click;
}
So weit so gut. Damit kann ich dann, wenn meine Komponente in den Designer ziehe, meine HeaderItems anlegen und bei denen jeweils die dazugehörigen Items.
Aber um den EventHandler zu setzen, kann ich nur in der Komponentenleiste unter dem FormDesigner die einzelnen Komponenten anklicken und dann bearbeiten.
Wie kann man einen Editor realisieren, wie es zum Beispiel bei ToolStrip oder beim MenuStrip der Fall ist? Kennt jemand dazu vielleicht ein Tutorial?
Oder sollte man dafür einen ganz anderen Weg gehen?
Super... das war's... vielen Dank für die Hilfe.
Jetzt schaut die Struktur auch wieder einigermaßen gut aus.
In diesem Fall wird MEF als DI-Container verwendet. Auf Anhieb hab ich jetzt keine Möglichkeit gefunden, dass ich da pro Thread andere Instanzen bekomme. Aber irgendwie muss das eigentlich gehen.
Das denke ich auch. Ich glaub sogar, dass ich die betroffene Stelle bereits gefunden habe
Task task1 = Task.Factory.StartNew(() => Products = IoC.Get<ProductsRepository>().GetAll());
Task task2 = Task.Factory.StartNew(() => CustomerGroups = IoC.Get<CustomerGroupsRepository>().GetAll());
Task task3 = Task.Factory.StartNew(() => FTPs = IoC.Get<FTPRepository>().GetAll());
Task.WaitAll(task1, task2, task3);
Die drei Abfragen sollen an der Stelle wohl parallel ausgeführt werden (die Daten werden in einer Art Cache gehalten) und das scheint das Problem zu verursachen.
Das kann ich ja noch relativ leicht beheben. Aber grundsätzlich ist es schon so, dass mehrere Threads parallel laufen können und auf den gleichen Context zugreifen.
Jetzt müsste ich also irgendwie die IoC-Klasse im Caliburn.Micro Framework dazu bringen, dass sie mir für verschiedene Threads unterschiedliche Instanzen von UnitOfWork liefert. Oder müsste das UnitOfWork irgendwie unabhängig von MEF erstellen.
Versteh ich das richtig, dass jeder Thread eine eigene Instanz von UnitOfWork erstellen sollte und damit dann auch jeder Thread seinen eigenen Kontext hat?
Ich hab jetzt probehalber mal meine Threads deaktiviert und dann klappt eigentlich alles wunderbar. Ist aber natürlich keine dauerhafte Lösung... die Threads haben schon einen Grund 😃
An einer Stelle hab ich das im Eingangsthread angerissene Problem:> Fehlermeldung:
Diesem Command ist bereits ein geöffneter DataReader zugeordnet, der zuerst geschlossen werden muss.
Hier sieht der Quellcode (im Service) so aus:
var updates = IoC.Get<ProductUpdatesRepository>().GetByProduct(product);
if (addGroups)
{
IList<CustomerGroup> groups = new List<CustomerGroup>();
foreach (var update in updates)
{
foreach (CustomerGroup group in IoC.Get<CustomerGroupsRepository>().GetByProductUpdate(update))
{
...
Das Fehler tritt auf, wenn die Daten aus dem CustomerGroupsRepository abgerufen werden sollen. Man kann das Ganze relativ leicht umgehen, indem ich im ersten foreach ein "ToList()" anhänge. Aber ist das der ideale Weg?
Ich weiss nicht ob ich das richtig verstehe, aber solche Abfragen gehören nicht ins "OnModelCreating". Die Methode kommt vor dem Initialisieren des eigentlichen Contexts. Da wird das Model aufgebaut. Da sollte eigentlich keine "Business-Logik" rein.
Lass das Model korrekt aufbauen. Danach hast du alles was du brauchst und dann führe deine initiale Abfrage von etwaigen Daten aus.
Im OnModelCreating hab ich ja auch nichts drin stehen... also die Methode hab ich gar nicht überschrieben. Deswegen verwirrt mich die Meldung ein bisschen
Danke für die Antworten. ich hab das jetzt angefangen umzusetzen (beim aktuellen Projekt sind das zum Glück nur 5 Repositories und daher gut zum Ausprobieren) und bin dann schon über ein genanntes Problem gestoßen
Für die Threadsicherheit bist Du zuständig.
Ich denke, dass genau das mein Problem ist, weil ich folgende Fehlermeldung erhalte:> Fehlermeldung:
The context cannot be used while the model is being created. This exception may be thrown if the context is used inside the OnModelCreating method or if the same context instance is accessed by multiple threads concurrently. Note that instance members of DbContext and related classes are not guaranteed to be thread safe.
Bei den aktuellen Statements handelt es sich um Stammdaten-Abfragen, die in einem Hintergrund-Thread beim Start der Anwendung erfolgen.
Wie kann ich jetzt hier für Threadsicherheit sorgen? Oder sagt die Fehlermeldung ganz was anderes aus?
Hallo zusammen,
ich bin gerade dabei, einige Anwendungen auf das Entity Framework umzustellen. Es handelt sich also um bestehende Datenbanken. Bisher wurde in einzelnen Repositories immer eine Tabelle gehandhabt.
Zum Beispiel eine Tabelle Customer hatte ein eigenes Repository mit den Methoden
In diesen Methode wurden per ADO.Net die Statements zusammengebaut und entsprechend ausgeführt. In den Methoden ist ansonsten keinerlei Logik vorhanden.
Jetzt mit dem EF hab ich das prinzipiell genauso aufgebaut. Allerdings bin ich gerade am tüfteln, wie ich die Context-Klasse, am besten handle. Es gibt in meinen Augen drei Möglichkeiten:
Was wäre jetzt die beste Möglichkeit?
Möglichkeit 1 fällt in meinen Augen fast aus, weil wenn man Daten aus einer Methode bekommt und diese Daten dann beim Weiterverarbeiten weitere Daten aus einer anderen Tabelle holen müssen, bekommt man eine Exception, dass der DataReader bereits einem anderen Command zugeordnet ist.
Wie handhabt ihr das?
Eine möglichkeit wäre, dass man das Fenster per HWND_BROADCAST in den Vordergrund holt.
Ich muss jetzt nur schauen, ob ich das aus dem Stegreif zusammenbekomme, weil ich aktuell kein Beispiel dazu zur Hand habe.
Man muss mit RegisterWindowMessage die Message WM_SHOWFIRSTINSTANCE|{0} anlegen
public static readonly int WM_SHOWFIRSTINSTANCE = WinApi.RegisterWindowMessage("WM_SHOWFIRSTINSTANCE|{0}", guid
Die Guid kommt dabei aus der AssemblyInfo.cs
[assembly: Guid("xxxx-xxxx-xxxx-xxxx-xxxx")]
Letztendlich kann man dann eine entsprechende Windows Message senden, um das Fenster in den Vordergrund zu holen:
WinApi.PostMessage((IntPtr)HWND_BROADCAST, WM_SHOWFIRSTINSTANCE, IntPtr.Zero, IntPtr.Zero);
Welchen Wert HWND_BROADCAST hat, weiß ich jetzt nicht auf Anhieb, aber das kann man sicherlich bei MSDN finden.
Hallo zusammen,
Ich hab mir ein ControlTemplate für UserControls erstellt. Im Speziellen geht es dabei um UserControls, die Dialoge darstellen sollen. Daher wollte nicht in jedem UserControl die Buttons für Ok und Abbrechen und die Titelleiste einfügen, sondern das ganze als ControlTemplate nur einmal realisieren und eben aus den einzelnen UserControl entsprechend verwenden.
Nur irgendwie bekommen ich das nicht bzw. mir fehlt da ehrlich gesagt komplett der Ansatz.
hier erst einmal das ControlTemplate
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ControlTemplate TargetType="UserControl" x:Key="DialogTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="LightBlue">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="Ok" x:Name="OkButton" BorderThickness="0" Padding="0" Margin="0" HorizontalAlignment="Left" />
<Button Grid.Column="1" Content="X" x:Name="CloseButton" BorderThickness="0" Padding="0" Margin="0" HorizontalAlignment="Right" />
</Grid>
<Border Grid.Row="1" Background="White">
<ContentPresenter x:Name="ContentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}" Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</Grid>
</ControlTemplate>
</ResourceDictionary>
Wenn ich das Template auf meine UserControls anwende funktioniert das vom Design her schon mal ganz gut. Aber wie kann ich von den UserControls aus auf die Buttons reagieren?
Ich verwende als MVVM Framework Caliburn.Micro. daher hab ich mir gedacht, dass ich per NamingConvention vielleicht ganz einfach darauf zugreifen kann
public void OkButton()
Aber das war wohl nichts.
Vielleicht kann mir da jemand auf die Sprünge helfen, wie ich das machen kann oder vielleicht hab ich auch vollkommen den falschen Ansatz.
Danke schon mal
Kann ich mir aber ehrlich gesagt kaum vorstellen.
ich hab andere Services auch schon am Laufen, von denen ebenfalls Daten in der Größenordnung gesendet werden. Ein Vergleich der Konfigurationen brachte mich aber auch nicht weiter. Es ist eher so, dass ich bisher damit noch nie Probleme hatte.
Ich hab auch jetzt keine weiteren Informationen dazu gefunden, dass es da eine Beschränkung gibt. Falls es wirklich daran liegt, muss ich mir dringend was anderes einfallen lassen
ich hab ein kleines Problem mit einem WebService, der in Azure läuft. Gleich mal vorweg: Das Problem tritt nicht auf, wenn ich das Azure-Projekt lokal starte.
Also der Service enthält eine Methode, die ein relativ großes XML zurückgeben kann. Wenn ich diese Methode aufrufe, erhalte ich am Client die folgende Fehlermeldung:> Fehlermeldung:
The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter
> .
The InnerException message was 'There was an error deserializing the object of type System.String. The maximum string content length quota (8192) has been exceeded while reading XML data.
This quota may be increased by changing the MaxStringContentLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader.
Line 319, position 17.'. Please see InnerException for more details.
InnerException hab ich natürlich schon gecheckt, aber die ist NULL
Google brachte mir schon viele Ergebnisse bezüglich dieser Fehlermeldung, aber keiner der gefunden Lösungsansätze hat bisher was gebracht.
Hier mal meine web.config, die auf dem Server verwendet wird:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="LargeDataBasic"
maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="MyService.Service">
<endpoint name="basicHttpEndpoint"
binding="basicHttpBinding"
bindingConfiguration="LargeDataBasic"
contract="MyService.Contracts.IMyService">
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Auf dem Client hab ich die Werte equivalent in der app.config gesetzt:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="myBasicHttpBinding"
maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="myBehaviour">
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint name="basicHttpEndpoint"
address="http://624997c2ff774xxxxxxxx8a944fa8102.cloudapp.net/myService.svc"
behaviorConfiguration="myBehaviour"
binding="basicHttpBinding" bindingConfiguration="myBasicHttpBinding"
contract="MyService.Contracts.IMyService" />
</client>
</system.serviceModel>
Ich such jetzt schon seit mehreren Tagen nach der Ursache für den Fehler und komm einfach nicht weiter. Vielleicht kann mir da jemand einen Denkanstoss dazu geben.
Danke schon mal
Perfekt... das war die Lösung.
Ich muss zwar den Code noch ein bisschen anpassen, weil ich das gleiche Dilemma auch noch an anderen Stellen habe, wo es wieder ein bisschen anders läuft, aber die Lösung naht 😃
Vielen Dank
Da das Ganze schon sehr generisch abläuft, ist das glaub ich nicht ganz einfach. Als erstes muss dabei erwähnt werden, dass der Name des Objekt Types nur als String bekannt ist. Aber das ist erst einmal nicht das Problem. Aber ich denke, dass man so vielleicht besser auf eine mögliche Lösung kommen könnte:
Die Neue Signatur der Methode sieht so aus:
public Func<T, bool> BuildFilter<T>(T obj, IList<ILookup> lookups) where T : IDomainObject
Ich geh nochmal einen Schritt zurück und zweige den Aufruf auch noch:
public function FetchDataFromTable(string tablename, IList<ILookup> lookups)
{
IList<IDomainObject> data = new List<IDomainObject>();
IDomainObject table = TableFactory.GetTable(tablename);
...
var selectedData = data.Where(ExpressionBuilder.Instance.BuildFilter(table, lookups));
}
Das Where erwartet einen echtes Object vom Type Func<IDomainObject, bool>
Ich hab mal versucht einen Wrapper aussenrum zu basteln
public Func<IDomainObject, bool> Test(IDomainObject obj, IList<ILookup> lookups)
{
MethodInfo genericMethod = this.GetType().GetMethod("BuildFilter");
MethodInfo finalMethod = genericMethod.MakeGenericMethod(obj.GetType());
return (Func<IDomainObject, bool>)finalMethod.Invoke(this, new object[] { obj, lookups });
}
Aber jetzt hab ich wieder in der letzten Zeile des Wrappers das Problem, dass ich nicht korrekt konvertieren kann (siehe Fehlermeldung oben). Einfach object zurückgeben funktioniert leider auch nicht, weil falscher Type.
Der Titel ist glaub ich jetzt nicht wirklich aussagekräftig, aber ich hab keine Ahnung, wie ich den Titel benennen soll. Ich hoffe, dass ich durch den folgenden Text meine Frage sauber formulieren kann, so dass klar ist, was ich letztendlich erreichen will.
Ich hab eine Methode, die mir einen Lamda-Expression zusammensetzt und compiliert zurück gibt. Das Ganze sieht so aus:
public static Func<DomainObject1, bool> BuildFilter(DomainObject1 obj, IList<ILookup> lookups)
{
ParameterExpression param = Expression.Parameter(obj.GetType(), "t");
Expression exp = null;
if (lookups == null || lookups.Count == 0)
{
ConstantExpression constant = Expression.Constant(true);
exp = Expression.IsTrue(constant);
}
else if (lookups.Count == 1)
exp = GetFilterExpression(obj.GetType(), param, lookups[0]);
...
return Expression.Lambda<Func<DomainObject1, bool>>(exp, param).Compile();
}
Das Ganze funktioniert wunderbar. Jetzt ist es aber so, dass DomainObject1 zusammen mit vielen anderen Objekten vom Interface _IDomainObject _ableitet. Natürlich soll die Methode mit allen Objekten verwendet werden können, die von IDomainObject ableiten. Die Signatur der Methode würde also folgendermaßen aussehen:
public static Func<IDomainObject, bool> BuildFilter(IDomainObject obj, IList<ILookup> lookups)
Jetzt hab ich aber das Problem, dass ich im letzten Statement eine ArgumentException bekomme:> Fehlermeldung:
Der ParameterExpression vom Typ "DomainObject1" kann nicht für Delegatparameter vom Typ "IDomainObject" verwendet werden.
Grund ist der, dass ein ParameterExpression vom Type _DomainObject1 _erzeugt wird.
Mein nächster Versuch war dann, dass ich den ParameterExpression eben mit einem anderen Type erzeuge:
ParameterExpression param = Expression.Parameter(typeof(IDomainObject). "t");
Dann funktioniert der Aufruf von GetFilterExpression nicht mehr. Auch kein Problem - hab ich mir gedacht, dass passe ich den eben auch noch an. Dann kommen wir in die nächste Methode:
private static Expression GetFilterExpression(Type realtype, ParameterExpression param, ILookup filter)
{
MemberExpression member = Expression.Property(param, realtype.GetPropertyExt(filter.Column));
ConstantExpression constant = Expression.Constant(filter.Value);
...
Hier hab ich jetzt das Problem, dass als realtype natürlich nur noch IDomainObject übergeben wird. In diesem Interface gibt es die die angegebene Property (aus filter.Column) nicht und es kracht wieder.
Ich weiß gerade echt nicht mehr, wie ich zum gewünschten Ergebnis kommen könnte. In meinen Augen müsste ich den Rückgabewert der Methode BuildFilter irgendwie dynamisch abändern. Aktuell gebe ich hier ein Objekt vom Type Func<DomainObject1, bool> zurück. Stattdessen bräuchte ich irgendwas in der Art: Func<var, bool>
Aber ich wüsste nicht, dass das möglich ist.
Vielleicht hat jemand einen Ansatz für mich, wie ich da weitermachen könnte.
Danke schon mal
Danke.
Hab jetzt eine ähnliche Lösung gefunden. Hab aber nicht abgeleitet, sondern stattdessen eine Wrapper-Klasse erstellt mit den Properties "Model", das das eigentliche Objekt enthält und außerdem auch noch die Property FileCorrect, die dann asyncron gesetzt wird, wenn das Model fertig überprüft ist. Funktioniert so jetzt ganz gut.
Ich hab folgendes Problem:
In einem DataGrid zeige ich Metadaten aus einer Azure-Datenbank an, Zu diesen Metadaten gehört außerdem auch noch ein File im BlobStorage. Grundlegend ist es erst einmal wichtig, dass die Daten aus der Datenbank angezeigt werden und das ist auch kein Problem.
Jetzt möchte ich in einem Background-Thread jeden Eintrag im BlobStorage überprüfen und falls diese Überprüfung fehl schlägt die Zeile im DataGrid farblich hervorheben.
Mein Ansatz ist bis jetzt folgender (der funktioniert aber nicht)
<DataGrid Grid.Row="1" AutoGenerateColumns="False" Name="Forms" Style="{StaticResource DataGridStyle}" IsReadOnly="True"
attached:DataGridMultipleSelection.SelectedItemsSource="{Binding SelectedForms}"
>
<DataGrid.Columns>
<DataGridTextColumn Header="Id" Binding="{Binding Id}" FontFamily="Consolas" />
...
</DataGrid.Columns>
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<DataTrigger Binding="{Binding Converter={StaticResource CheckFileConverter}, IsAsync=True}" Value="false">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
</DataGrid>
Der CheckFileConverter sieht dann so aus:
public class CheckFileConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is Form)
{
bool result = false;
Form formular = value as Form;
BlobDataProvider provider = new BlobDataProvider();
provider.OverrideConnectionString(...);
// überprüfen, ob Datei überhaupt existiert
result = provider.Exists(0, "3/" + formular.Id);
...
return result;
}
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
So. Ich hab damit gehofft, dass der Converter durch das "IsAsync" asynchron im Hintergrund ausgeführt wird, aber dem ist leider nicht so. Stattdessen wird die GUI gesperrt, bis alle Converter Aufrufe durch sind und das kann seeeehr lange dauern 😃
Wie kann ich dieses Problem lösen? Es sollte so aussehen, dass die Daten angezeigt werden und dann mit der Zeit die erkannten fehlerhaften Einträge markiert werden.
Ich sollte dazu noch erwähnen, dass ich das Objekt an dem die DataGrid-Zeilen gebunden sind nicht verändern, also keine zusätzliche Property einführen kann. Sonst würd ich das so lösen und einfach per NotifyPropertyChanged dem UI sagen, dass sich was geändert hat, wenn die Überprüfung durch ist. Aber es muss doch auch eine andere Lösung geben, oder?
Danke, der Ansatz hört sich gut an. Da muss ich mal schauen, ob ich das finde und vor allem, ob ich da schreiben kann (UAC usw. 😃 )
Danke für die Antworten
Über die Richtlinien hab ich schon nachgedacht und jetzt auch nochmal den ganzen Tag damit rumgespielt. Allerdings komm ich damit nicht dahin, wo ich hin will. Das Problem dabei ist, dass sich das scheinbar immer auf alle Verbindungen auswirken würde. Da die Netzwerkstandorte aber ein Sicherheitsfeature sind, will ich die nicht bei allen unseren Kunden deaktivieren. ich glaub, da würden mir einige ganz gewaltig auf die Finger klopfen.
Wifi-Direct kann ich leider nicht verwenden, weil einfach zuviele Geräte (Tablets, Smartphones) nicht dafür zertifiziert sind und zum Teil auch immer irgendwelche eigenen Implementierungen dafür verwendet werden.
Im Moment geh ich ehrlich gesagt schon in die Richtung, dass ich eine entsprechende Anleitung beim ersten Verbinden aufpoppen lasse in der steht, was man anklicken soll (aber selbst dann werden sicherlich einige immer noch auf 'öffentlich' klicken und damit die Windows-Firewall komplett dicht machen). Die Abfrage erfolgt ja nur beim ersten mal und dann merkt sich das System die entsprechende Einstellung.
Ich schreibe gerade an einem kleinen Programm, mit dem ich Daten von einem Tablet synchronisieren will. Dabei soll es auch eine Möglichkeit geben per WLan zu synchronisieren, wenn am Arbeitsplatz-Rechner kein Internet zur Verfügung steht (man braucht lediglich eine WLan-Karte/Stick). In diesem Fall erstellt das Tablet einen Hotspot, der Rechner findet den Hotspot (an Hand des Namens) und verbindet sich dann mit diesem Hotspot. Das funktioniert alles ein wand frei.
Jetzt kommt's aber: Wenn sich der Rechner mit dem Hotspot verbindet, erscheint von Windows her die Abfrage nach dem Netzwerkstandort (Privat, Arbeitsplatz, Öffentlich). Diese Abfrage stört unsere Kunden. Vor allem auch, weil sie nicht wissen, was sie da anklicken müssen (wobei das auch noch wichtig ist, weil das letztendlich auf die Einschränkungen der Firewall Auswirkungen hat)
Da es sich bei dieser Hotspot-Verbindung immer um eine sichere Arbeitsplatz-Verbindung handelt, würde ich gerne das Fenster, das vom System her aufpoppt verhindern. Gibt es dazu eine einfach Möglichkeit? Ich stelle die WLan-Verbindung über die WlanApi her. Evtl. gibt es da irgendeine Einstellung im WLan-Profile mit dem man diese Einstellung gleich festlegen kann.
Die andere - unschöne Möglichkeit - Möglichkeit ist, dass ich per FindWindow das Fenster suche und fernsteuere, aber das möchte ich nach Möglichkeit vermeiden, weil das böse Folgen haben kann, wenn sich mal doch ein echtes Netzwerk verbindet und die Abfrage bringt.
Ich weiß, dass die Frage nicht direkt was mit .NET zu tun hat, aber vielleicht hat ja dennoch jemand eine Idee. Vielen Dank schon mal
Durch deine Antwort bin ich ja darauf gekommen. Danke nochmal dafür
Manchmal ist die Lösung ganz einfach, aber gefunden hab ich die Message nicht ums verrecken.
Für die, die es interessiert hier die Lösung (hab beim Löschen der Zeile auch noch was geändert, weil die ursprüngliche Sache nicht richtig funktioniert hat):
Win32.SendMessage(txtLog.Handle, WM_SETREDRAW, 0, IntPtr.Zero);
txtLog.Select(txtLog.TextLength, 0);
txtLog.SelectionColor = color;
txtLog.AppendText(message);
while (txtLog.Lines.Length > 99)
{
txtLog.SelectionStart = 0;
txtLog.SelectionLength = txtLog.Text.IndexOf("\n", 0) + 1;
txtLog.SelectedText = "";
}
txtLog.Select(txtLog.TextLength, 0);
Win32.SendMessage(txtLog.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
txtLog.Invalidate();
WM_SETREDRAW ist folgendermaßen definiert
private const int WM_SETREDRAW = 0x000B;
Hallo zusammen,
ich hab eine RichTextBox, die Logeinträge live und in Farbe ausgibt. Damit nicht zuviel Speicher verbraten wird, hab ich die Anzeige auf 100 Zeilen beschränkt. Das heißt, wenn mehr als 100 Zeilen in der RTB bereits vorhanden sind, wird die erste Zeile wieder gelöscht, wenn eine neue Zeile hinzukommt.
Das funktioniert auch ganz gut mit dem folgenden Code
txtLog.Select(txtLog.TextLength, 0);
txtLog.SelectionColor = color;
txtLog.AppendText(message);
if (txtLog.Lines.Length > 100)
{
txtLog.Select(0, txtLog.GetFirstCharIndexFromLine(1));
txtLog.SelectedText = String.Empty;
txtLog.SelectionStart = txtLog.TextLength;
}
Das Problem an der Sache ist, dass damit immer kurz an den Anfang der RTB gescrollt wird, die Zeile gelöscht wird und dann wieder ans Ende zurück gescrollt wird. Man hat also ein ständiges flackern auf dem Bildschirm.
Gibt es irgendeine Möglichkeit, wie man die erste Zeile löschen kann ohne das die Textbox scrollt? Wichtig dabei ist, dass die Farben auch nicht verloren gehen.
Ich hab mir ein seltsames Konstrukt gebastelt und scheinbar bin ich damit in eine Sackgasse gelaufen.
Folgendes Szenario: Ich hab eine Listbox, die Daten in TextBlocks anzeigt. Wenn eine Zeile selektiert wird, wird das DataTemplate ausgetauscht und ein paar TextBlocks durch TextBoxes ersetzt. Das funktioniert wunderbar. Ich kann dann per Tabulator auch durch die TextBoxen durchspringen.
Wenn ich was in einer dieser TextBoxen eingebe, springt ein PropertyChangedEvent des darunter liegenden Objekts an und das wiederrum feuert ein CollectionChanged Event in der ObservableCollection, die an die ListBox gebunden ist.
Und damit ist es dann vorbei... Die TextBoxen verlieren den Fokus und stattdessen ist die ListBox selbst fokusiert.
Scheinbar reagiert da das ViewModel aus irgendeinen Grund auf die Änderung der Collection und aktualisiert das Binding wodurch eben der Fokus verloren geht. Gibt es da vielleicht eine Möglichkeit, wie man das umgehen kann?
Noch eine kleine Randinformation:
Ich verwende Caliburn.Micro und das entsprechende ViewModel ist von "Screen" abgeleitet.
Jetzt hab ich doch noch selber eine Lösung gefunden bzw. hab den Fehler gefunden.
Im UserControl hab ich ja eingebaut, dass ich per Binding auf das Score-Objekt im CodeBehind zugreif. Und hier hab ich zu wenig angegeben
Ursprünglich hatte ich folgendes im XAML stehen:
<TextBlock Text="{Binding Score.Arrow1.Value}" />
Hier bekam ich dann eben die Fehlermeldung, dass Score im ViewModel nicht vorhanden ist. Daher hab ich dann den DataContext gesetzt, was allerdings dazu geführt hat, dass der View der das UserControl verwendet die Properties des ViewModels nicht mehr gefunden hat.
Die Lösung ist letztendlich ganz einfach. Weg mit dem DataContext wie "Briefkasten" schon geschrieben hat und stattdessen das Binding genauer spezifizieren:
<TextBlock Text="{Binding ElementName=SC, Path=Score.Arrow1.Value}" />
Und jetzt klappt's auch mit der Nachbarin.
Vielen Dank an alle für Erklärungen und die Denkanstöße
Irgendwie versteh ich das aber nicht.
<TextBlock Text="{Binding Path=Score1,RelativeSource=
{RelativeSource Mode=FindAncestor,AncestorType={x:Type local:UserControlName}}}"></TextBlock>
Dieses Binding kann ich nicht im UserControl setzen, weil das UserControl ja Score1 nicht kennt. Score1 ist eine Property im ViewModel vom Type Score. Insgesamt gibt es davon 6 Properties (Score1 - Score6)
Der View zum ViewModel soll für diese 6 Properties ein UserControl zur Anzeige verwenden. In diesem UserControl gibt es ein DependencyProperty vom Typ Score (in meinem Fall heißt die Property auch Score)
Wenn ich jetzt im UserControl die Angabe vom DataContext (siehe oben) weglasse bekomme ich folgende Fehlermeldung
System.Windows.Data Error: 40 : BindingExpression path error: 'Score' property not found on 'object' ''SheetViewModel' (HashCode=4029665)'. BindingExpression:Path=Score.Arrow1.Value; DataItem='SheetViewModel' (HashCode=4029665); target element is 'TextBlock' (Name='_arrow1'); target property is 'Text' (type 'String')
Das ist auch irgendwie klar, weil der DataContext ja dann auf das ViewModel zeigt, in dem es aber die Property Score nicht gibt. Das UserControl soll das Binding ja aus dem CodeBehind holen.
Ich hab langsam das Gefühl, dass ich vollkommen den falschen Ansatz habe. Ich denke, dass es nicht sonderlich gut gelöst ist, wenn ich ein UserControl verwende, das selbst CodeBehind hat und das Ganze dann innerhalb von einer MVVM Umsetzung. Vielleicht sollte ich mir das nochmal durch den Kopf gehen lassen.
Ich find das ehrlich gesagt auch seltsam mit dem SetValues. Aber das war ein Versuch, wie ich ein Problem mit dem Binding umgehe 😃
wenn ich im UserControl mit Binding arbeite, bekomme ich in der Trace-Ausgabe folgende Fehlermeldung
BindingExpression path error: 'Score1' property not found on 'object' ''ScoreControl' (Name='')'. BindingExpression:Path=Score1; DataItem='ScoreControl' (Name=''); target element is 'ScoreControl' (Name=''); target property is 'Score' (type 'Score')
Im UserControl hab ich dabei den DataContext gesetzt, damit ich auf die Prtoperty im CodeBehind zugreifen kann.
DataContext="{Binding RelativeSource={RelativeSource Self}}"
vielleicht hab ich ja schon einen grundlegenden Fehler in der ganzen Sache.
Wie würde denn die Syntax mit dem ChangeDelegate aussehen?
Hallo zusammen,
ich hab mir ein UserControl gebaut, das ein Objekt als DependencyProperty beinhaltet. Das Ganze sieht folgendermaßen aus:
public static readonly DependencyProperty ScoreProperty =
DependencyProperty.Register("Score", typeof(Score), typeof(ScoreControl));
public Score Score
{
get { return base.GetValue(ScoreProperty) as Score; }
set
{
base.SetValue(ScoreProperty, value);
SetValues();
}
}
In der Methode SetValues werden dann aus dem Score-Objekt einzelne werte ausgelesen und in mehreren TextBlocks im XAML ausgegeben. Das geschieht vom Code aus und ohne Binding.
Jetzt kommt das Control, das das oben genannte UserControl einbindet (mehrmals, aber das spielt glaub ich keine Rolle). Der Code in XAML sieht so aus:
<FitaScore_Controls:ScoreControl Margin="0" HorizontalAlignment="Center" Score="{Binding Score1}"/>
Im ViewModel hab ich dann das Property Score1 ganz normal vom Type Score angelegt:
private Score _score1;
public Score Score1
{
get { return _score1; }
set
{
_score1 = value;
NotifyOfPropertyChanged(() => Score1);
}
}
Aus irgendeinem Grund, wird aber im UserControl nichts angezeigt. Ich bekomme auch keinen Fehler und im Trace steht auch nichts drin, was auf einen Fehler hindeuten könnte.
Breakpoints UserControl bringen auch nichts... es wird nie einer davon angesprungen, wie wenn die Property im UserControl nie aufgerufen werden würde.
Ich hab jetzt überhaupt keine Ahnung mehr, was ich noch kontrollieren könnte.
Achja... vielleicht spielt das auch eine Rolle: Ich verwende Caliburn.Micro als MVVM Framework. Bisher hatte ich damit auch nie Probleme, aber das bekomm ich jetzt einfach nicht hin. Wobei ich aber bisher auch kaum was mit DependencyProperties gemacht habe.
Das schwierige auf dem Hauptbildschirm hast du ja schon erledigt. Auf dem zweiten Bildschirm ist ja keine Taskbar. Das heißt, man kann wirklich den Fullscreen verwenden.
ich hab mir dazu ein paar Extensions geschrieben, die allerdings unschönerweise auf WinForms verweisen. Über SystemParameters dürfte das aber genauso funktionieren
public static void FillSecondaryScreen(this Window window)
{
Rect area = ScreenBounds(window.GetSecondaryScreen());
window.Left = area.Left;
window.Top = area.Top;
window.Width = area.Width;
window.Height = area.Height;
window.WindowState = WindowState.Maximized;
window.WindowStyle = WindowStyle.None;
}
public static int GetSecondaryScreen(this Window window)
{
if (Screen.AllScreens.Length == 1)
return 0;
int primary = window.GetCurrentScreen();
for (int secondary = 0; secondary < Screen.AllScreens.Length; secondary++)
{
if (secondary == primary)
continue;
return secondary;
}
throw new Exception("no secondary screen found");
}
public static int GetCurrentScreen(this Window window)
{
Screen screen = Screen.FromHandle(new WindowInteropHelper(window).Handle);
for (int i = 0; i < Screen.AllScreens.Length; i++)
{
if (screen.Equals(Screen.AllScreens[i]))
return i;
}
throw new Exception("target screen was not found");
}
public static Rect ScreenBounds(int screenNumber)
{
if (screenNumber < Screen.AllScreens.Length)
return Screen.AllScreens[screenNumber].Bounds.ToRect();
throw new Exception(String.Format("Screen '{0}' is not available", screenNumber));
}
(Teile des Codes sind vielleicht ein bisschen spezifisch auf unsere Software, aber im groben und ganzen ist es glaub ich klar.
Ich schiebe das Fenster einfach auf Koordinaten des zweiten Bildschirms und maximiere es dann dort. In meinem Fall ist es ja auch gewollt, dass das Fenster in einen echten Fullscreen geht und in der Regel wird man auf dem zweiten Bildschirm auch nichts anderes haben.
Problematisch könnte es allerdings sein, wenn man eine zusätzliche Taskleiste auf dem zweiten Bildschirm hat.
Ich hab aber auch noch eine weitere Methode, die evtl auch noch helfen könnte. ich muss allerdings zugeben, dass ich nicht mehr weiß, wo ich diese gefunden habe. Diese nehm ich für den PrimaryScreen her, sollte man aber auch auf dem Secondary verwenden können. Durch "MonitorFromWindow" wird ja der richtige Monitor gesucht.
// Make window borderless
this.WindowStyle = WindowStyle.None;
this.ResizeMode = ResizeMode.NoResize;
// Get handle for nearest monitor to this window
WindowInteropHelper wih = new WindowInteropHelper(this);
IntPtr hMonitor = MonitorFromWindow(wih.Handle, MONITOR_DEFAULTTOPRIMARY);
// Get monitor info
MONITORINFOEX monitorInfo = new MONITORINFOEX();
monitorInfo.cbSize = Marshal.SizeOf(monitorInfo);
GetMonitorInfo(new HandleRef(this, hMonitor), monitorInfo);
// Create working area dimensions, converted to DPI-independent values
HwndSource source = HwndSource.FromHwnd(wih.Handle);
if (source == null) return; // Should never be null
if (source.CompositionTarget == null) return; // Should never be null
System.Windows.Media.Matrix matrix = source.CompositionTarget.TransformFromDevice;
RECT workingArea = monitorInfo.rcWork;
Point dpiIndependentSize =
matrix.Transform(
new Point(
workingArea.Right - workingArea.Left,
workingArea.Bottom - workingArea.Top));
// Maximize the window to the device-independent working area ie
// the area without the taskbar.
// NOTE - window state must be set to Maximized as this adds certain
// maximized behaviors eg you can't move a window while it is maximized,
// such as by calling Window.DragMove
this.Top = 0;
this.Left = 0;
this.MaxWidth = dpiIndependentSize.X;
this.MaxHeight = dpiIndependentSize.Y;
this.WindowState = WindowState.Maximized;
Edit: Hmmm... das Ding hab ich schon ewig nimmer angesehen und jetzt seh ich, dass da ein Fehler drin ist. Im unteren Codeschnipsel darf am Ende natürlich nicht Left und Top auf 0 gesetzt werden, sondern muss auf workingArea.Left bzw. workingArea.Right gesetzt werden
hmmm... also doch ein Problem mit den 8.3 Namen. Hätt ich mir eigentlich denken können.
Ich versteh aber trotzdem nicht, warum das auf manchen wenigen Rechnern trotzdem funktioniert.
Mal was ganz anderes über das wir gerade gestolpert sind.
Man hat in einem Verzeichnis zwei Dateien:
test1.txt
test2.txt
mit Wildcards bekommt man dann beide Dateien:
DIR *.txt
Jetzt benennen wir die zweite Datei um in test2.txt2
Was würdet ihr jetzt erwarten, wenn man nun wieder mit DIR *.txt die Dateien auflisten lässt?
Ich würde eigentlich erwarten, dass jetzt nur die Datei test1.txt aufgelistet wird. Stattdessen werden aber wieder beide Dateien aufgelistet.
Damit das ganze noch ein bisschen verwirrender wird: Dieses Phänomen scheint nicht überall aufzutreten, wenn auch auf den meisten Rechnern. Aber kann mir das mal jemand erklären?
Bzw. weiß jemand, wie ich in diesem Fall dann DIR verwenden muss, um nur die Dateien zu bekommen, die wirklich mit .TXT aufhören?
Danke schon mal
Wie sehr ihr das eigentlich mit den ganzen Begriffen, für stink normale Programme? Was bedeuten die ganzen Begriffe eigentlich?
Es gibt da ganz allgemein den Begriff "Programm" oder englisch "Application". Was ist der Unterschied zu einer "App"? Ist eine "App" nur ein kleines Programm? Oder ist es ein Programm, dass auf einem Smartphone/Tablet läuft? Letzteres stimmt jetzt dann ja auch nicht mehr mit den neuen Windows 8 Metro Apps, die ja sowohl auf einem Desktop als auch auf Tablets laufen? Oder ist das einfach eine Ausnahme gemäß dem Motto "Ausnahmen bestätigen die Regel"?
Im Moment definiere ich die Sachen noch so:
Application: Eine vollwertiges, komplexes Programm mit mehreren Screens/Dialogen, das auf einem Arbeitsplatz oder einem Server läuft.
Tool: Kleines Werkzeug-Programm zum kleine Arbeiten sowohl auf Desktop/Server Systemen als auch auf Smartphones etc.
App: Kleines Programm auf Smartphone und Tablets mit eingeschränktem UI, das eben auf die Umgebung angepasst ist.
Was gibt es denn sonst noch so?
Ok. Dann lag ich also mit meiner Annahme richtig, dass das eigentlich keinen Sinn macht. Die anderen Beispiel sind ja alle klar und ich glaub, die hab ich auch entsprechend richtig erklärt (Ob er es verstanden hat, wird sich noch zeigen)
Die Frage kam eben auf, als er ein Programm von mir als Beispiel angesehen hat. Davor ist mir das nie aufgefallen 😃
Danke für die Antworten
Eigentlich ist das ja eine Anfängerfrage. Aber ich hab mir auf Grund einer Frage darüber mal Gedanken gemacht.
Zum einen ist es mir vollkommen klar, dass man mit Interfaces eine gewisse Abstraktion von Objekten erreichen kann. Sinnvollstes Einsatzgebiet ist wohl die lose Kopplung von Komponenten (Trennung GUI - Logik etc.)
Aber was mir aufgefallen ist, ist folgendes:
IList<String> list = new List<String>();
Warum nehm ich da ein Interface her? Wirklich eine blöde Frage muss ich zugeben. Das lustige ist, dass ich das immer so mache ohne darüber nachzudenken.
Ich hab mir die Arbeit gemacht und ein paar Quelltexte von OpenSource-Projekte durchgesehen und auch da gibt es sehr viele Entwickler, die das ebenso machen.
Aber wie erklär ich erklär ich jetzt einem Anfänger, warum ich das so mache? Ich weiß es ja selbst nicht 😃
Da helfen meine Lösungsanstätze im oben genannten Thread auch nicht wirklich, da diese voraussetzen, dass das Video beim bearbeiten des Graph nicht laufen (geht ja anders gar nicht soviel ich weiß)
Aber die Idee mit dem Handle ist nicht schlecht. Ich hab da jetzt zwar auch keine Erfahrung damit, aber mit Hilfe des Handles solltest du eigentlich den Inhalt abgreifen können und daraus ein WriteableBitmap (oder besser ein D3DImage) rendern können, das dann eben auf der zweiten Form angezeigt wird. Es ist dann allerdings kein echtes Video mehr auf der Form sondern lediglich die Ausgabe des Videos von Form1.
Ob man dann das WritableBitmap bzw D3DImage in Windows Forms schnell genaug auf die Oberfläche schreiben kann, ist dann wieder die andere Frage. Aber zumindest beim D3DImage sollte das auf jeden Fall möglich sein, wenn man wieder auf Handle-Ebene arbeitet.
Einfach ist das Unterfangen aber auf jeden Fall nicht. Rein mit .NET Werkzeugen wird man da ziemlich sicher scheitern, denke ich.
Ok. Doch noch nicht erledigt.
Auf meinem PC hier funktioniert es ein wand frei. Auf meinem Laptop mit einer GForce Quadro FX 1600M mit 256MB Grafikspeicher läuft es nur noch sehr stockend, wenn ich den VisualBrush aktiviert habe.
Ich muss also noch nach einer performanteren Lösung suchen.
@Cat: Danke. Das hab ich schonmal irgendwo gehört, aber vollkommen vergessen. Muss ich mir nochmal anschauen. Wobei ich ja dann dennoch wohl auf die Win32 API ausweichen muss. Aber mal schauen. Da mach ich mir noch irgendwann mal Gedanken. Lösungen gibt es auf jeden Fall dafür genügend denke ich.
@Ujr: Die Sache mit DirectShow ist allgemein viel zu wacklig. Wenn man sich mit seinem Rechner auskennt, kann man sich in der Regel selber helfen und ein paar Codec-Packs installieren, die man eben braucht. Aber der Ottonormal-Verbraucher sieht einfach nur, dass es nicht geht und hat keine Ahnung warum. Dass er durch Spiel XY, Irgendeinen Webcam-Chat und noch einen DVD-Player seine ganzen Filter-Einstellungen auf dem Rechner verändert hat und sich diese auf das gesamte System auswirken, weiß er ja nicht. Daher geben wir fest vor, welche Filter verwendet werden und liefern die auch mit der Software mit aus. Damit sind wir ziemlich unabhängig vom System und es ist sehr unwahrscheinlich, dass uns eine andere Software dazwischen funkt.
Eine andere, sicherere Möglichkeit haben wir leider noch nicht gefunden, wie man es schafft, dass Videos (immer das gleiche Format) auf jedem System immer laufen. Wenn da jemand eine Idee hat, nur her damit.
Ok. Jetzt hab ich zwei Lösungen. Einmal die oben erwähnte, die ja eher an WPF vorbei geht. Aber es funktioniert sehr zuverlässig und das schöne ist, dass man direkt in den Graph eingreifen kann (auch eine Sache, die ich dringend benötige)
Dann aber die schönere Möglichkeit: Ich hab http://wpfmediakit.codeplex.com/ gefunden und von da hab ich jetzt zum Testen mal das MediaUriElement verwendet. Wie ujr schon vorgeschlagen hat, hab ich davon dann einen VisualBrsuh im zweiten Fenster erstellt. Funktioniert einwandfrei und man kann so dann auch noch ein bisschen mit den Effekten rumspielen.
Jetzt muss ich dann nur noch das MediaUriElement mal genauer anschauen, ob man da den Graph anpassen kann oder gegebenenfalls noch das Ding ein bisschen erweitern.
Es würde wahrscheinlich auf diese Weise auch mit dem normalen MediaElement funktionieren, aber da man da keinerlei Möglichkeiten hat auf den Graph zuzugreifen, ist das dann für mich ziemlich uninteressant.
Achja: Um die ursprüngliche Frage selbst zu beantworten: Ich hab einfach ein zweites Fenster erstellt, wobei ich die Größe an System.Windows.Forms.Screen.AllScreens[1].WorkingArea angepasst habe. WindowStyle = none und WindowState = maximized machen dann noch den Rest, damit der komplette Monitor ausgefüllt wird.
Ein bisschen unschön, dass man auf eine Forms-Sache zugreifen muss, aber da find ich vielleicht bei Zeiten auch noch eine andere Lösung
Das war mein erster Versuch in der Richtung und das hat auf meinem Rechner ganz gut funktioniert. Dann wollt ich das Konzept auf dem Testrechner zeigen und da war dann nichts mehr mit synchron. Diese Arbeitsweise ist halt sehr abhängig von der Rechnerperformance.
Ich hab jetzt allerdings einen Test gestartet, dass ich meinen Graph selber zusammenbau und mit einem Pin Tee Filter versehe. Dadurch, dass ich zwei Fenster habe, kann ich auch zwei Handles rausholen. Das eine Handle (Beamer) bekommt den Stream als Vollbild indem ich IVideoWindow auf die volle Größe festlege (SetWindowPosition). Für den Lehrerschirm setze ich die WindowPosition bloß auf einen Bereich. Ich glaube, dass ich damit alles hinbekommen sollte. Ist nur leider vollkommen an WPF vorbei programmiert und gerade bei einem Multimedia-Framework wie WPF finde ich das ehrlich gesagt ziemlich schade.
Ja. Das wär ja genau der Ansatz mit dem Pin Tee Filter. Nur wie kann man bei WPF dann die Ausgaben einem Control/Window zuweisen, wenn man keine Handles hat? Also für ein Window bekomm ich ja noch ein Handle mit dem WindowInteropHelper, aber auf dem Lehrerschirm will ich die Ausgabe ja nicht im gesamten Fenster machen sondern nur auf einem Control und das dürfte doch dann nicht klappen.
ich muss dazu sagen, dass ich das jetzt noch nicht ausprobiert habe, weil ich mir im moment lediglich Gedanken darüber machen, wie man das am sinnvollsten lösen kann.
EDIT: Ideal wär eigentlich eine Lösung, dass man auf dem Lehrerschirm das mediaElement hat und ganz normal in WPF manier arbeiten kann. Den Stream des MediaElements müsste man dann anzapfen und eine zweite Ausgabe auf das zweite Window legen, das auf dem Beamer angezeigt wird.
Das heißt, ich bräuchte eine Lösung, wie ich den Stream des MediaElements anzapfen kann.
Hallo alle zusammen,
ich suche gerade einen Ansatz, wie man ein Video auf zwei Monitoren ausgeben könnte. Es handelt sich dabei um eine Präsentations-Software bei der das Video zum einen auf dem Lehrerbildschirm in einem kleinen Bereich ausgegeben wird und zum anderen auf dem Beamer in Vollbild.
Realisieren will ich das ganze eigentlich per WPF, wobei das jetzt noch offen ist.
Wie kann man das am besten anpacken? Ich befürchte, dass einzelne Bilder dafür einfach zu langsam sein werden. Evtl. bräuchte man eine Lösung, dass man über einen Pin Tee Filter die Ausgabe auf zwei VideoRenderer splittet, wodurch ich aber zu dem Problem komme, dass man bei WPF keine Window Handles für die einzelnen Controls hat, soviel ich weiß.
Vielleicht kann man irgendwie einen Stream erzeugen, der dann gleichzeitig von zwei MediaElementen wieder gegeben wird, aber auch da fehlt mir der Ansatz.
Hat da vielleicht jemand ein paar Ideen?
Vielen Dank schon mal
Meint ihr, dass dotPeek und JustDecompile kostenlos bleiben? Bei den beiden Herstellern bin ich mir da nicht so sicher, ob die wirklich das Tool auch weiterhin kostenlos lassen. Vorallem, wenn sie sehen sollten, dass Red-Gate damit Geld verdienen kann (was ja noch in den Sternen steht)
Wirklich Sorgen mach ich mir dahingehend zwar nicht, weil ich an und für sich mit ILSpy ganz zufrieden bin, aber eure Meinung würd mich da schon interessieren.
Ich find es auf jeden Fall schön, dass es innerhalb einer so kurzen Zeit gleich mehrere mächtige Alternativen gibt.