Ja das hatte ich mir angeschaut, aber da ist keine Bindung möglich um mehre Inputparameter zu berücksichtigen. Daher muss ich es jetzt anders lösen und das Datenmodell diesbezüglich aufbohren
Hallo Community,
ich versuche eine Art mehrstufige Sortierung bei einer ListBox
in WPF hinzubekommen. Dazu folgendes Beispiel (ich verichte auf die ganzen PropertyChanges etc. aufrufe der Übersichtlichkeit halber)
public class Data
{
public string Name,
public string Category
public int Index // das ist der Index aus der Quelle von dem die Daten kommen, dieser kann mehrfach herkommen
public int Offset
}
Ich habe eine ObservableCollection<Data>
die habe ich an eine CollectionViewSource
gebunden und die wieder rum an die Listbox. Über
<PropertyGroupDescription Converter="{StaticResource dataToGroupConverter}" CustomSort="{StaticResource GroupComparer}"/>
Habe ich einen Converter der die Category zu einer GruppenID macht und der Comparer sortiert die Gruppen dann entsprechend nach. Es gibt noch TemplateSelektoren die ja nach GruppenID ein anderen Style laden aber das spielt gar nicht so eine Rolle.
Vereinfacht wird dann im ListBox
folgendes angezeigt:
- Category 1
- "[Name]" // Instance OBJ 1 hat dann Index 0
- "[Name]" // Instance OBJ 2 hat Index 3
- Category 2
- "[Name]" // Instance OBJ 3 hat dann Index 1
- "[Name]" // Instance OBJ 4 hat dann Index 2
- Category 3
- "[Name]" // Instance OBJ 5 hat dann Index 1
- "[Name]" // Instance OBJ 6 hat dann Index 3
Im Moment habe ich eine Problem mit der Sortierung innerhalb einer Gruppe. Die ist aktuell der Reihenfolge wie sie hinzugefügt wurde zur Collection. Was ich jetzt bräuchte das ist eine Arte zweite Sortierung in Abhängigkeit der ersten Sortierung. D.h.
Im ersten Schritt sortiere ich alle Mitglieder einer Kategory nach dem Index
dann kommt das Beispiel oberen aus. Nun habe ich eine Offset
Wert der sagt das mein Position verschoben werden kann (am Beispiel)
// Nach erster Sortierung
- "Kategory 1"
- "Wert 1" // Obj: Name = "Wert 1", Category = "Kategory 1", Index = 0, Offset = 0
- "Wert 1" // Obj: Name = "Wert 2", Category = "Kategory 1", Index = 3, Offset = 0
- "Wert 2" // Obj: Name = "Wert 3", Category = "Kategory 1", Index = 4, Offset = -2
// Nach zweiter Sortierung
- "Kategory 1"
- "Wert 2" // Obj: Name = "Wert 3", Category = "Kategory 1", Index = 4, Offset = -2
- "Wert 1" // Obj: Name = "Wert 1", Category = "Kategory 1", Index = 0, Offset = 0
- "Wert 1" // Obj: Name = "Wert 2", Category = "Kategory 1", Index = 3, Offset = 0
Ich verschiebe also visuell durch den Offset
Wert meine Position innerhalb der Gruppe.
Meine erste Idee war die SortDescriptions
bzw. CollectionViewSource
im Code-behind zu ListCollectionView
zu casten und CustomSort
zu nutzen. Das wird aber auf alle Elemente der ItemsSource
angewandt. Da kenn ich ich als den "GruppenIndex" noch nicht. Eine weitere Idee war eine zweite sortierte Liste mitlaufen zu lassen aus denen ich dann die "GruppenIndexes" berechnen und dann den Offset dazunehme. Aber dann habe ich eine weitere Datenstruktur die ich pflegen muss.
Was irgendwie fehlt das man einen weiteren Comparer für die Items innerhalb einer Gruppe anhängen kann.
Vielleicht hat einer eine Idee?
Grüße
Das kenne ich nicht muss ich mal schauen ob das Auswirkungen hat Danke
Hallo Community,
ich versuche mich nach Jahren wieder in WPF reinzuarbeiten, habe aber das Gefühl alles vergessen zu haben. Ich versuche ein CustomControl von einer ComboBox zu bauen das neben der ComboBox einen ResetButton anzeigen zu hat.
public class ResetableComboBox : ComboBox
{
// STATIC PROPERTIES
public static readonly RoutedEvent ResetEvent;
// STATIC CONSTRUCTORS
static ResetableComboBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ResetableComboBox), new FrameworkPropertyMetadata(typeof(ResetableComboBox)));
ResetEvent = EventManager.RegisterRoutedEvent(nameof(Reset), RoutingStrategy.Bubble, typeof(RoutedEventArgs), typeof(ResetableComboBox));
}
// FIELDS
private Button _resetButton;
// METHODS
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_resetButton = Template?.FindName("resetButton", this) as Button;
if (_resetButton != null)
{
_resetButton.Click += ResetButton_Click;
}
}
private void ResetButton_Click(object sender, RoutedEventArgs e) => OnReset();
protected virtual void OnReset() => RaiseEvent(new RoutedEventArgs(ResetEvent));
// EVENTHANDLER
public event RoutedEventHandler Reset
{
add { AddHandler(ResetEvent, value); }
remove { RemoveHandler(ResetEvent, value); }
}
}
}
Der C# Code klappt auch soweit wenn ich den ResetButton drücke dann wird auch das Event geworfen. In der Generic.xaml
habe ich dann in den beiden ComboxTemplates (habe mir per VS > WPF Designer > ComboBox Selektion > Edit Template das komplette Template ausgeben lassen und an mein neues Control angepasst)
<ControlTemplate x:Key="ComboBoxTemplate" TargetType="{x:Type customControls:ResetableComboBox}">
<Grid x:Name="templateRoot" SnapsToDevicePixels="true">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Width="0"/>
<ColumnDefinition MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Width="0"/>
</Grid.ColumnDefinitions>
<Popup x:Name="PART_Popup" AllowsTransparency="true" Grid.ColumnSpan="2" IsOpen="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
<Themes:SystemDropShadowChrome x:Name="shadow" Color="Transparent" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{Binding ActualWidth, ElementName=templateRoot}">
<Border x:Name="dropDownBorder" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
<ScrollViewer x:Name="DropDownScrollViewer">
<Grid x:Name="grid" RenderOptions.ClearTypeHint="Enabled">
<Canvas x:Name="canvas" HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
<Rectangle x:Name="opaqueRect" Fill="{Binding Background, ElementName=dropDownBorder}" Height="{Binding ActualHeight, ElementName=dropDownBorder}" Width="{Binding ActualWidth, ElementName=dropDownBorder}"/>
</Canvas>
<ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Contained" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Grid>
</ScrollViewer>
</Border>
</Themes:SystemDropShadowChrome>
</Popup>
<Button x:Name="resetButton" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="2" Style="{StaticResource ComboBoxResetButton}" Margin="-1,0,0,0" />
<ToggleButton x:Name="toggleButton" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.ColumnSpan="2" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ComboBoxToggleButton}"/>
<ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" Content="{TemplateBinding SelectionBoxItem}" ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" IsHitTestVisible="false" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
Wenn ich nun das ganze in einem Window einbinden klappt auch alles. Meine Frage wäre jetzt, müsste es nicht möglich sein auf Window
Ebene ein neuen Style anzulegen für dieses Control.
<Style TargetType="{x:Type customControls:ResetableComboBox}">
<Setter Property="Background" Value="AliceBlue"/>
</Style>
Aber das ändert die Farbe nicht. Im WPF Buch von Huber wird im Kapitel "CustomControls" auf Window Ebene im Style auch das Template überschrieben, ich war aber der Meinung dass das auch so gehen müsste.
Grüße
Daniel
internal class Rectangle
{
public int X { get; set; }
}
internal class Control
{
private Rectangle _bounds;
public Control()
{
_bounds = new Rectangle { X = 5 };
}
public int X => _bounds.X;
}
internal class Button : Control
{
}
Habe es mal kurz durchgespielt
static void Main(string[] args)
{
var button = new Button();
Console.WriteLine($"X (OLD): {button.X}");
// Basisklasse öffentlich, Rectangle Klasse öffentlicht
var bounds = (Rectangle)typeof(Control)
.GetField("_bounds", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
.GetValue(button);
bounds.X = 6;
Console.WriteLine($"X (NEW): {button.X}");
// Basisklasse nicht öffentlich, Rectangle Klasse nicht öffentlicht
var boundsOBJ = button
.GetType()
.BaseType // Rekursiv suchen ggf.
.GetField("_bounds", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
.GetValue(button);
// Autoproperties bekommen einen autogenierten Namen der __BackingField enthält
boundsOBJ.GetType().GetField("<X>k__BackingField", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(boundsOBJ, 20);
Console.WriteLine($"X (NEW) WAY 2: {button.X}");
Console.ReadLine();
}
Im wesentlichen kannst du alles was öffentlich ist auch nutzen für Reflection ansonsten muss man es eben generisch machen. Mit Reflection bekommst du fast alles geliefert und kannst auch Änderungen vornehmen (mit Ausnahmen). Eventuell falls du Reflection häufig brauchst würde ich über Caching der typen etc. nachdenken. Es gibt einige Blogbeiträge zum Thema Performance bei Reflection.
public ref int X => ref _bounds.X;
Wenn du weißt dass die Property nur ein Fascade für ein zugrundeliegendes Objekt ist, kannst du via Reflection auch die das Object _bounds
einfach direct holen und prüfen ob deren X
Property ein Setter hat. Ggf. wenn es weitere Objekte gibt hangelst du dich durch. Sollte X
ein Auto-Property sein erzeugt der Compiler automatisch ein Feld nach einem bestimmten Namensschema (das kannst du dir i Debugger auslesen). Das Feld solltest du via Reflection schreiben können.
Erstmal ein Dankschön an alle die geantwortet haben. Die Variante mit Exceptionhandling sowie die Sache mit using, habe ich auch jetzt auf dem Schirm. Gerade das Kommentar von Toub finde ich dort sehr hilfreich.
😄 Achso ich versuche gerade die Stelle in den Docs zu finden.
Danke Abt,
Welches Dokument meinst du mit IIRC?
Hallo Community,
ich habe eine Frage zum Thema Task bzw. async/await.
static async void Main(string[] args)
{
await DoSomthingAsync();
await DoSomthingAsync2();
}
static async Task DoSomthingAsync()
{
await Calling();
}
static Task DoSomthingAsync2()
{
return Calling();
}
static Task Calling() => Task.Delay(1);
Meine Frage ist ob es einen Unterschied macht, ob ich auf den Task awaite wie in DoSomthingAsync oder den Task durchroute wenn der Aufrufer sowieso ein await macht?
Das einzige was mir auffällt ist dass wenn ich schon ein await mache:
static async Task DoSomthingAsync3()
{
await Calling();
return Calling();
}
Das ich dann den letzten Aufruf durchrouten kann.
Cool jetzt funktioniert es wieder und manchmal kann ein Zeichen entscheident sein! Vielen Dank für die Hilfe! 👍
P.S. Gerade noch gefundeb Visual Studio Version Ranges Demystified
Danke für den Hinweis, leider hat sich dadurch nichts geändert. Ob ich die Sprache im Addin ändere oder die VS Spracheinstellung, beides führt zur selben Fehlermeldung!
Hallo Community,
ich stehe im Moment auf dem Schlauch. Ich habe gerade versucht ein selbst geschriebenes VS Addin für das neue VS2019 fit zu machen. Das Addin selber stellt einen Einstellungsdialog bei der Erstellung spezifischer Projekte bereit. Bei der Installation wird angegeben dass dieses Addin für die installierte VS Version nicht installiert werden kann.
12.04.2019 08:31:04 - Microsoft VSIX Installer
12.04.2019 08:31:04 - -------------------------------------------
12.04.2019 08:31:04 - vsixinstaller.exe version:
12.04.2019 08:31:04 - 16.0.2264
12.04.2019 08:31:04 - -------------------------------------------
12.04.2019 08:31:04 - Command line parameters:
12.04.2019 08:31:04 - C:\Program Files (x86)\Microsoft Visual Studio\Installer\resources\app\ServiceHub\Services\Microsoft.VisualStudio.Setup.Service\VSIXInstaller.exe,C:\Repositories\VisualStudioIntegration\Test\bin\Debug\Test.vsix
12.04.2019 08:31:04 - -------------------------------------------
12.04.2019 08:31:04 - Microsoft VSIX Installer
12.04.2019 08:31:04 - -------------------------------------------
12.04.2019 08:31:04 - Initializing Install...
12.04.2019 08:31:05 - Erweiterungsdetails...
12.04.2019 08:31:05 - Identifier : Test.92c071c0-95c3-492f-a523-c8fc6000ad4e
12.04.2019 08:31:05 - Name : Citavi 6 Add-on Template
12.04.2019 08:31:05 - Author : Daniel
12.04.2019 08:31:05 - Version : 0.0.5.0
12.04.2019 08:31:05 - Description : Add a wizard to initialize a new Citavi 6 add-on project.
12.04.2019 08:31:05 - Locale : en-US
12.04.2019 08:31:05 - MoreInfoURL :
12.04.2019 08:31:05 - InstalledByMSI : False
12.04.2019 08:31:05 - SupportedFrameworkVersionRange : [4.6,4.7.2)
12.04.2019 08:31:05 -
12.04.2019 08:31:05 - SignatureState : Unsigned
12.04.2019 08:31:05 - Unterstützte Produkte :
12.04.2019 08:31:05 - Microsoft.VisualStudio.Community
12.04.2019 08:31:05 - Version : [15.0,16.0)
12.04.2019 08:31:05 - Microsoft.VisualStudio.Pro
12.04.2019 08:31:05 - Version : [15.0,16.0)
12.04.2019 08:31:05 - Microsoft.VisualStudio.Enterprise
12.04.2019 08:31:05 - Version : [15.0,16.0)
12.04.2019 08:31:05 -
12.04.2019 08:31:05 - Verweise :
12.04.2019 08:31:05 - Voraussetzungen :
12.04.2019 08:31:05 - -------------------------------------------------------
12.04.2019 08:31:05 - Identifier : Microsoft.VisualStudio.Component.CoreEditor
12.04.2019 08:31:05 - Name : Visual Studio core editor
12.04.2019 08:31:05 - Version : [15.0,16.0)
12.04.2019 08:31:05 -
12.04.2019 08:31:05 - Signaturdetails...
12.04.2019 08:31:05 - Extension is not signed.
12.04.2019 08:31:05 -
12.04.2019 08:31:05 - Er wird nach passenden Produkten gesucht...
12.04.2019 08:31:05 - Installiertes Produkt gefunden - Globaler Pfad
12.04.2019 08:31:05 - Installiertes Produkt gefunden - Visual Studio Enterprise 2019
12.04.2019 08:31:05 - VSIXInstaller.NoApplicableSKUsException: Diese Erweiterung kann auf den derzeit installierten Produkten nicht installiert werden.
bei VSIXInstaller.ExtensionService.GetInstallableData(String vsixPath, String extensionPackParentName, Boolean isRepairSupported, IStateData stateData, IEnumerable`1& skuData)
bei VSIXInstaller.ExtensionPackService.IsExtensionPack(IStateData stateData, Boolean isRepairSupported)
bei VSIXInstaller.ExtensionPackService.ExpandExtensionPackToInstall(IStateData stateData, Boolean isRepairSupported)
bei VSIXInstaller.App.Initialize(Boolean isRepairSupported)
bei VSIXInstaller.App.Initialize()
bei System.Threading.Tasks.Task`1.InnerInvoke()
bei System.Threading.Tasks.Task.Execute()
--- Ende der Stapelüberwachung vom vorhergehenden Ort, an dem die Ausnahme ausgelöst wurde ---
bei Microsoft.VisualStudio.Telemetry.WindowsErrorReporting.WatsonReport.GetClrWatsonExceptionInfo(Exception exceptionObject)
Die Versionsnummern (VS19 = 16.0) scheinen laut meinen Recherchen korrekt. Referenziert werden von VS nur die
Microsoft.VisualStudio.TemplateWizardInterface.dll (Version 8.0), envdte.dll (Version 8.0) und die Microsoft.VisualStudio.Coreutility.dll (Version 16.0). Alle Verweise werden gefunden und sind auch korrekt.
Vielleicht hat ja jemand einen Hinweis für mich.
Ich denke dabei geht es vor allem, das die Projekte die noch auf WinForms und WPF bauen einen Grund zu geben, auf .net Core umzusteigen, so dass .net Full das zeitliche segnen kann. Das ist erst mal positiv. Was ich wirklich schade finde ist, dass es kein wirkliches Statement zu einer UI Technologie gibt. Ich arbeite nun seid 8 Jahren mit C# angefangen mit
WinForms
WPF
WinRT
UWP
und nun ist halt Web-Gedöns über PWA der Hype.
Es wäre doch mal ganz angenehm sich für einen Basistechnologie zu entscheiden und dann aber richtig zu promoten und vielleicht auch mal sich zu trauen etwas Cross-Plattform fähiges zu bauen. WPF ist wirklich nice, schade das man jetzt zu dem HTML Gedöns übergegangen ist. Vielleicht gibt es dem ganzen aber noch einen Push für andere Open Source Projekte wie z.B. Avalonia (Da gibt es ja mittlerweile eigene Open Source Editoren)
Wenn man natürlich schaut ist das alles schon eine positive Entwicklung, schauen wir mal wo die Reise hingeht. Wenn jetzt noch VS Open Source werden sollte, dann fr.. ich sprichwörtlich den Besen. 😄
Wobei das nur die .net Core Portierungen sind
This repo contains WinForms for .NET Core. It does not contain the .NET Framework variant of WinForms
Hallo Community,
ich hätte mal eine Frage die wohl eher C++ betrifft als C#. Ich würde gern eine Erweiterung für den Windows Explorer schreiben, so dass dort eine Verknüpfung (vgl Bild im Anhang) und eine Auflistung an Ordnern angezeigt wird wie es bei OneDrive und anderen Dienste (Dropbox macht das glaub ich auch) angezeigt wird. Ich hatte schon mal im Netz geschaut, muss aber gestehen dass ich da nicht weit gekommen bin, weil ich auch nicht genau mir vorstellen kann mit welchen Stichwörter ich suchen sollte. Andere Erweiterungen des Explorers z.B. des Ribbon Bandes oder des Kontextmenu mit C++ oder C# (z.B. Sharpshell) hatte ich schon gefunden.
Vielleicht hat jemand so etwas in der Art schon gemacht oder kann mir einen Tipp geben.
Beste Grüße
Daniel
Das war mir schon klar, die Frage war, wie der Decompiler den Code wieder mit dem Bezeichner herstellt statt mit der ganzen Zahl. Macht er aber gar nicht
public class EnumTestClass
{
public EnumTest EnumTestProperty
{
get
{
return (EnumTest) 1;
}
}
}
Er macht dass nur wenn auch die referenziert DLL woher der Enum stammt gefunden wird. Andernfalls wird korrekterweise die Zahl wiedergegeben. In meinem ersten Test hat er die referenzierte Lib noch gefunden und dann korrekterweise daraus
public class EnumTestClass
{
public EnumTest EnumTestProperty => EnumTest.Alpha;
}
Für meine Ausgangsfrage bedeutet dass aber, dass bei einer Umstellung von einem Enum -> auf ein FlagEnum alle Bibliotheken die dieses Enum verwenden neu kompiliert werden müssen, weil sonst nicht gewährleistet werden kann, dass der richtige EnumWert zugewiesen wird.
Okay dass hat wieder Licht ins Dunkeln gebracht
Hier noch das Bild
Also ich habe noch mal geschaut aber irgendwie stehe ich auf dem Schlauch: Soweit ich das mit (ildasm) sehe wird doch nur die ganze Zahlwert gespeichert:
Das Testprojekt ist im Anhang.
Das mit der ersten Frage hatte ich mir schon indirekt gedacht, aber die Frage mit dem Decompiler, wie er das macht. Wenn im IL Code nur eine Ganzzahl steht, dass beim dekombilierten Code wieder der ursprüngliche Bezeichner (z.B. Alpha) wieder steht.
Hallo Community,
ich habe mal zwei Fragen:
1.) Stimmt es dass Enum Werte im IL Code als Zahl gespeichert werden und dann der entsprechende verknüpfte Wert zur Laufzeit geholt wird?
Wenn ja: 2) Wie schaffen es Dekompiler beim wiederherstellen des Codes aus dieser Zahl den korrekten Wert zu ermitteln, also so das wieder der textuelle Wert darsteht?
Hintergrund ist der: Angenommen es gibt zwei Bibliotheken A und B. B referenziert A und hat in seinem Code
Bibliothek A
public enum Test
{
Alpha = 0
Beta = 1,
Gamma =2,
}
Bibliothek B
public Test TestEnum => Test.Gamma;
Wenn mann sich den IL Code anschaut steht da nun die 1. Und daher stellt sich die Frage wie das Decompiler machen, wenn die referenzierte Bibliothek A nicht auf dem Ziel System ist.
Hintergrund ist der, dass es darum geht, aus dem Enum Test -> ein FlagsEnum zu machen, dann ändern sich aber die Zahlen ja, weil es dann 2-Potenzen sein müssen und dass müsste ja dann zu Seiteneffekten kommen, weil dann aus der 2 die in der Bibliothek B kompiliert wird zur Laufzeit vielleicht dann zu Beta wird.
Beste Grüße
Liebe Community,
wenn man im Windows Explorer eine/mehre Dateien gleichen Datentyps selektieren bekommt man ja im Kontextmenü über "Öffnen mit..." eine Liste der damit verknüpften Programme angezeigt. Genau diese Liste würde ich gern auslesen, so das sich den Pfade und die entsprechenden Parameter um die Liste in einer eigenen Anwendung anzuzeigen und die Programme mit einem Dateipfad zu öffnen. Soweit ich das verstehe muss ich dafür die Registry durchforsten, aber bisher habe ich nur die Standardanwendung und manchmal 1 oder 2 Programme die auch in der Liste standen gefunden, aber nie die komplette Liste. Daher die Frage ob jemand da einen Tipp hat, wie ich diese anzapfen könnte!
Ich habe schon in die Registry geschaut, aber da scheint nicht die original List zu stehen
MfG
Daniel
Ich habe nach längerem Suchen folgende Anleitung gefunden, nach der ich vor gangen bin und dann ging auch alles.
Guten Abend,
ich arbeite gerade mich duch die Anleitung einen Wizard für ein Project Template für Visual Studio zu erstellen. Dazu habe ich die folgende Microsoft-Anleitung mit angeschaut. Woraus ich nicht ganz schlau werde. Am Anfang werden in der Solution drei Projekte erstellt. Eines für das Projekt Template, eins für den Wizard und ds VSIX Projekt. Weiter unten wird aber die IWizard Implementierung aber den VSIX Projekt hinzugefügt. Über sehe ich da etwas?
Gruß Daniel
Oder du benutzt eine BulkObservableCollection<T> in dem du die BulkCollection<T> von Visual Studio nimmst oder du baust sie dir selbst.
Hallo Community,
vielen Dank für die Antworten. Ich habe mir alles angeschaut und bin letzten endlich doch beim Google Forms gelandet. Alles etwas einfacher gehalten, aber es hat so weit funktioniert
MfG
Daniel
Es soll so in Richtung poll gehen mit Shared Link. Jemand bekommt einen Link von mir, kann dadurch teilnehmen, hat n-Stimmen (kann ich definieren) die er per Klick auf die verschiedenen Antwortmöglichkeiten verteilen kann. Ich sehe zum Schluss welche die meisten Votes bekommen haben. Man findet einige (ich habe mit Sicherheit noch nicht alle angeschaut), viele bieten soweit ich das sehe nicht die Möglichkeit wie oben beschrieben oder jeder der teilnehmen will, muss sich mit einem Account anmelden (um die Eindeutigkeit der antworten zu gewährleisten)
Hallo Community,
erstmal danke für die Antworten. Zielpublikum sind andere Studenten/Entwickler. Will das für ein paar Studiensachen nutzen. Über die Links bin ich bisher noch nicht wirklich zu einem Ergebnis gekommen. Werde vielleicht mal Google Forms probieren. Wichtig ist, dass die Leute die Antworten sollen keinen Account zu einem Dienst brauchen, quasi via Einladungslink antworten können. Es geht neben Wünschen auch mal darum Vortragsthemen als Ranking darzustellen und wie oben erwähnt auch mal Feature usw. Da für die UNI ist die Sache mit den Issue-Tracker hier etwas zu viel. Sonst hätte ich da mal geschaut.
Gruß
Daniel
Hallo Community,
da ich mit Google nicht so richtig was zufriedenstellendes gefunden habe, frage ich mal hier nach ob jemand einen Tipp hat. Ich suche eine einfache Software (Web) um ein paar Leuten per Link die möglichkeit zu geben aus einer Liste an z.B Wünsche an Softwareentwicklung mt einer von mir festgelegten Anzahl an Votes für Wünsche zu stimmen und ich sehe dann zum Schluss welche Wünsche die meisten Stimmen hat. Muss nichts aufwendiges sein gern kostenls entweder direkt nutzbar ider zum selber hosten.
Gruß
Daniel
Welche Eigenschaften hast du den Beim Button für Anchor und Margin gesetzt?
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
MenuItem MN = sender as MenuItem;
string ImageSender = MN.CommandParameter.ToString();
image_load(ImageSender);
}
Es wurden ja einige Ansätze genannt was du besser machen kannst und willst. Eine spontane Idee (ungetestet) waär im Xaml bei MenuItem die Tag Eigenschaft einfach frech zu nutzen. Dort in RelativSource Binding mit AncestorTyp auf Image Das ja im Visual Tree weiter oben kommen müsste. Dann würdest das oben mit einem cast machen
var menuItem = sender as MenuItem;
var image = menuItem.Tag as Image;
image_load(image);
Musste probieren, ob das so geht. Die anderen Stichwörter das mit MVVM und enem Command machen, waäre auch eher mein Favourit.
Solche Informationen, gehören nicht zum Button. UI Elemente irgendwelche Informationen zu Daten mitzugeben ist nicht sehr schön und hat auch nichts mit der Aufgabe der UI Elementen zu tun. Du solltest dir ein geeignetes Datenmodell überlegen. Darin speicherst du Position und Zustand (Welche Figur steht drauf, Figur von wem usw). Wird ein Button gedrückt evaluierst du die Position und schaust dann in deinem Datenmodell nach.
Du könntest doch einfach ein DataGrid nehmen. Und als Model eine Tabelle. Und wenn du z.B. Hex einblenden willst. blendest du entsprechend die Zeile ein. Und wenn du es bearbeitbar machen willst. Bauchst du als CellEditTemplate ein Template mit entsprechend einer Textbox und ansonsten nimmst du Textblocks/Lables oder was auch immer zur Anzeige.
Sehr merkwürdig, dass ich da so verschiedene Sache gelesen habe. Wenn es wirklich so einfach ist wie es Sir Rufo beschreibt, wäre es ja wirklich easy. Na mal sehen. Besten Dank für die Antworten
Hallo Community,
ich wollte mal fragen ob jemand schon mal mit dem webcal Protokoll Erfahrungen gemacht habe. Ich habe eine externe Seite (nicht von mir) die ich nach Datumsangaben parse und dann eine ICS Datei erstellen. Die ICS Datei zu erstellen ist kein Problem, dafür nutze ich das rianjs/ical.net. Jetzt überlege ich wie ich im Netze diese Datei so freigebe, dass sie von E-Maildiensten (Exchange, outlook.com) abonniert werden könnte und auch Änderungen dafür mitbekommt. Wenn ich die Internetquellen richtig verstehe, müsste ich webcal Protocoll nutzen, dass der Subscriber Änderungen dafür mitbekommt. (Wenn ich selber die Datei abbonieren würde, könnte ich ja auch pollen und schauen ob es eine Änderung gab)
Jemand vielleicht ein Idee. Ich könnte mir vorstellen die Datei halt z.B. auf einem Rasperry Pi an Netz zu hängen mit Portfreigabe usw. und man greift dann entsprechend darauf zu. Die Erstellung der ICS würde als Dienst laufen.
Vielleicht hat ja jemand Erfahrung damit.
Wenn ich das richtig überblicke wird dein Graph ja nicht vom SerialPort gespeist. Du schreibst einen Wert rt jedes Mal rein. Dieser muss aber soweit ich sehe ja immer 0 sein. Da der Wert ja hier
double rt = 0;
private void timer1_Tick(object sender, EventArgs e)
{
rt = rt + 0.1;
}
gesetzt wird und so weit ich sehe wird der Timer nie gestartet. D.h. der Wert bleibt immer 0 und damit wird der Graph auch immer auf der x-Achse liegen. So ganz macht der Code auch keinen Sinn. Der Graph stellt keine Werte da (wenn er denn was anzeigen würde) sondern nur in Abständen wenn das DataReceived Event geworfen wird, wird der rt und der sin(rt) geschrieben.
Das stimmt nicht ganz. Denn gemass den Fall es wäre eine Collection würde sie bei mir im If Statement herausfliegen. A=s String und tostring sind da schon in unterschied. Also weiter oben wurde auf den Debuger hingewiesen. Dann einfach einen BreakPoint setzen mit einer Condition (row[] as String== null) dann wird sich zeigen ob da in der DataTable irgendwo eine Liste versteckt. Wenn ja muss er die Erstellung der DataTable prüfen. Wenn nicht ist hier eigentlich alles gezeigt worden was er bräuchte.
Mal nur so eine Frage hast du die Columns im Grid selber erstellt oder generiert dir das DataGrid (AutoGenerateColumns=true) die Spalten aus dem was die gebundene DataTable hergibt?
Wenn du sie selbst erstellst, dann müsste es ja in etwa so aussehen
<DataGridTemplateColumn Header="Pfade">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock>
<Hyperlink Click="openFile_Click" TargetName="{Binding}" ToolTip="{Binding}" TextDecorations="{x:Null}">
<Image Source="{Binding Converter={StaticResource stringToImageConverter}}" Width="30" Height="30" />
</Hyperlink>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Sinn gemäß.
@Pille, weil im Bild einfach mal die Schrift von oben nach unten lesen?
List<String> filePathes = new List<String>();
foreach (DataRow row in table.Rows)
{
if (row["Verlinkungen"].ToString().Trim() != "")
{
String[] pathes = row["Verlinkungen"].ToString().Split(';');
foreach (String path in pathes)
{
filePathes.Add(path);
}
row.SetField("Verlinkungen_Verlinkungen", filePathes);
filePathes.Clear();
}
}
row["Verlinkungen"].ToString()
Wenn hierbei nun das oben beschriebene Verhalten rauskommt, dann ist in dieser Zelle kein String sondern eine Collection hinterlegt. Zumal ich nicht ganz verstehe warum er es so umständlich macht. Außerdem kannst du den Code etwas zusammenfassen.
foreach (var row in table.Rows)
{
var pathAsString = row["Verlinkungen"] as string;
if(string.IsNullOrEmpty(pathes) || string.IsNullOrWhiteSpace(pathes)) continue;
var pathes = paths.Split(new string[]{";"},StringSplitOptions.RemoveEmptyEntries).ToList();
row.SetField("Verlinkungen_Verlinkungen", pathes);
}
So im XAML nun an die ItemsSource das ganze binden. Ob die Darstellung nun passt kann man schlecht ohne Xaml Schnipsel sagen.
Entweder so wie du es beschrieben hast. Oder du bindest den String an die ItemsSource des ItemsControls und schiebst einen Converter mit rein der den String mit string.split() aufsplittet und eine Liste zurück gibt. Der Rest wie oben beschrieben.
Ja stimmt man sollte von manchen Situationen in denen man nur eine unkonventionelle Frickellosung hatte nicht auf anderer schliessen. Ein ItemsControl ist deutlich besser dafür geeignet. Die Liste der FilePathes an die ItemsSource gebunden und als ItemsTemplate eine DataTemplate verwenden das das eigentlich schon fast so ähnlich wie der erste XML Code aufgebaut ist. Nur das das TargetName auf den DatenContext gebunden werden muss weil das ja der FilePath ist.
Also wenn ich das richtig verstehe hast du ein DatGrid wo in einer Zelle mehre Links angezeigt werden? Wenn ja dann nimm doch ein TextBlock. DU SCHREIBST deine FilePath einfach alle in eine Liste. Diese Liste bindest du an die Inlines Eigenschaft des TextBlocks. Das geht aber nicht direkt soweit ich mich erinnere. Du kannst das indirekt über ein Dependency Eigenschaft machen in einer abgeleiteten Klasse von TextBlock. Und das Binding erfolgt dann mithilfe eines Converters. Dieser iteriert durch die gebundene Liste und erzeugt für jeden FilePath ein Hyperlink Objekt.
Hey ich kenne jetzt die Lib nicht aber das ist doch WinForm oder? Vielleicht hilft das weiter!
Mhmm ich dachte auch es wäre einfacher...
Also du hast die Wahl. Entweder du überschreibst das ControlTemplate des Expanders (MSDN) dort findest du den Auszug
Dort findest du diesen Abschnitt
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ToggleButton OverridesDefaultStyle="True"
Template="{StaticResource ExpanderToggleButton}"
IsChecked="{Binding IsExpanded, Mode=TwoWay,
RelativeSource={RelativeSource TemplatedParent}}">
<ToggleButton.Background>
<LinearGradientBrush EndPoint="0.5,1"
StartPoint="0.5,0">
<GradientStop Color="{DynamicResource ControlLightColor}"
Offset="0" />
<GradientStop Color="{DynamicResource ControlMediumColor}"
Offset="1" />
</LinearGradientBrush>
</ToggleButton.Background>
</ToggleButton>
<ContentPresenter Grid.Column="1"
Margin="4"
ContentSource="Header"
RecognizesAccessKey="True" />
</Grid>
</Border>
Da hier ein Grid mit zwei Spalten verwendet wird und die zweite Spalte quasi auf voller länger angepasst wird, würde dein Code dann auch funktionieren. Oder du nutzt die Variante mit dem AttachedProperty (Link) Ich persönlich würde eher Variante zwei wählen
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander >
<Expander.HeaderTemplate>
<DataTemplate>
<Grid local:ParentContentPresenter.HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Beschriftung 1 " Grid.Column="0"/>
<TextBlock Text="Beschriftung 2 " Grid.Column="1"/>
<TextBlock Text="Beschriftung 3 " Grid.Column="2"/>
<Button Click="Button_Click" Grid.Column="3" HorizontalAlignment="Right">
<Button.Content>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Datensatz hinzufügen: "/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</Button.Content>
</Button>
</Grid>
</DataTemplate>
</Expander.HeaderTemplate>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
Und das AttachedProperty wie im Link beschrieben.
Unter Expander.Header steht Stackpanel. Das ersetzt du mit Grid und darunter als Grid.ColumnsDefinitions (Danach mal Google und das so anwenden wie ich oben beschrieben habe)
In der Template Eigenschaft für den Header des Groupstyle nimmst du ein Stackpanel zur Ausrichtung. Du könntest auch ein Grid mit Grid Columns (Alle Definition mit Width=Auto ausser bei den Column wo der Button drin ist da setzt du die Width=* und dem Button noch die HorizontalAlignmentRight Eigenschaft geben. Das sollte dann passen.
Es wäre vielleicht gut ein Screenshot zur Visualisierung. Etwas Code wie du das ganze ausliest an Daten und auch ein paar angaben. I I Ddpi Scaling (100 150 175 Prozent) usw. Dann kann man mehr nachvollziehen 😉
Ja das wäre der direkte Weg beim Converter könntest du aber evaluieren und auf Fehler reagieren. Im Prinzip passiert aber das gleiche dort
Die Schlüsselwörter sind Task und async und await. Im Eneffekt (auf dem Handy ist es schlecht zu überblicken der Code) ich würde ein Task machen statt einem Thread und den aufrufen
Das geht über ein Converter denke ich am besten. In deinem Template für den Grouping greifst du ja auf die Eigenschaft Name zu. Das Objekt das dahinter steht ist ein GroupItem oder so ähnlich. Es besitzt neben dem Namen und dem ItemsCount auch eine Eigenschaft Items. Das ist eine Liste aller Objekte die eine Gruppe bilden. Einfach ein Converter bauen und das Binding auf Items. Im Converter nichts anderes machen als ein paar Sicherheitsprufungen ob der Count ungleich Null ist usw. Dann einfach das 1. Objekt aus der Liste (ist ja dein Model) und da bekommst du den Namen her.