Laden...
B
Brendan myCSharp.de - Member
Softwareentwickler Dabei seit 28.11.2006 39 Beiträge
Benutzerbeschreibung

Forenbeiträge von Brendan Ingesamt 39 Beiträge

28.02.2018 - 15:25 Uhr

Hallo Abt,

Vielen Dank für Deine Erläuterungen.
Dadurch ist mir nun einiges klarer geworden.
In meinem Fall werde ich - leider - den Weg der Email-Verschlüsselung gehen müssen, da dies so gefordert ist.
Macht das Ganze natürlich etwas komplizierter, da meine Kunden dann die gleiche Digital ID wie ich haben müssen.

Anbei möchte ich mich entschuldigen, falls mein erstes Posting den Eindruck erweckt haben sollte, ich hätte keine Vorarbeit geleistet, sondern sofort eine Anfrage im Forum eingestellt.
Tatsächlich tue ich mir bereits seit ein paar Stunden die Finger wund googeln und habe auch schon zwei Varianten der Verschlüsselung ausprobiert, die mich aber nicht weiter gebracht haben.
Sorry!

28.02.2018 - 14:02 Uhr

Hallo,

Tut mir leid, ich habe bisher keine Emailverschlüsselung per Code gemacht und bin was das angeht ein absolutes Greenhorn.
In der Zwischenzeit hatte ich auf https://stackoverflow.com/questions/10439418/programmatically-encrypt-outlook-email-using-inspector einen Codeschnipsel gefunden, den ich in meine Applikation einbaute, wobei ich nun noch das Problem habe, dass der Button zur Verschlüsselung disabled ist.
Ich hoffe, dass hierzu in meinem lokal installierten Outlook nichts angepasst werden muss.


        private void AddOutlookEncryption(ref Microsoft.Office.Interop.Outlook.MailItem mailItem)
        {
            try
            {
                CommandBarButton encryptBtn;
                mailItem.Display(false);
                encryptBtn = mailItem.GetInspector.CommandBars.FindControl(MsoControlType.msoControlButton, 718, Type.Missing, Type.Missing) as CommandBarButton;

                if (encryptBtn == null)
                {
                    //if it's null, then add the encryption button
                    encryptBtn = (CommandBarButton)mailItem.GetInspector.CommandBars["Standard"].Controls.Add(Type.Missing, 718, Type.Missing, Type.Missing, true);
                }

                encryptBtn.Enabled = true;

                if (encryptBtn.Enabled)
                {
                    if (encryptBtn.State == MsoButtonState.msoButtonUp)
                    {
                        encryptBtn.Execute();
                    }
                }

                mailItem.Close(Microsoft.Office.Interop.Outlook.OlInspectorClose.olDiscard);
            }
            catch (Exception ex)
            {
                //[...]
            }
        }

28.02.2018 - 13:09 Uhr

Hallo,

Ich wollte wissen, wie man bei Microsoft.Office.Interop.Outlook ein MailItem bzw. die zu versendende Mail verschlüsseln kann.
Wenn Du mir dabei weiterhelfen könntest.

28.02.2018 - 12:00 Uhr

Hallo,

Ich bin gerade dabei in einer WPF-Anwendung mit VS2015 mittels Microsoft.Office.Interop.Outlook.MailItem eine Methode zu schreiben, die im code-behind Emails versendet.
Das funktioniert bereits.
Nun möchte ich diese Mail - da sie ein Login für einen neuen User enthält - auch noch verschlüsseln - nicht signieren.
Wie macht man das am geschicktesten?

Vielen Dank im voraus!

Anbei noch mein Code, den ich für den Versand geschrieben habe:


private void SendEmailWithNewPassword()
{
	try
	{
		var app = new Microsoft.Office.Interop.Outlook.Application();
		StringBuilder body = new StringBuilder();

		if (app != null)
		{
			Microsoft.Office.Interop.Outlook.MailItem mailItem = app.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem);

			switch (CurrentWorkingState)
			{
				case WorkingState.AddNew:
					mailItem.Subject = daoMaskText.GetText("TextSubjectNewAccount", LanguageLibrary.GetCurrentLanguage());
					body.Append(daoMaskText.GetText("TextMessageNewAccount", LanguageLibrary.GetCurrentLanguage()) + Environment.NewLine + Environment.NewLine);
					break;
				case WorkingState.ResetPassword:
					mailItem.Subject = daoMaskText.GetText("TextSubjectNewPassword", LanguageLibrary.GetCurrentLanguage());
					body.Append(daoMaskText.GetText("TextMessageNewPassword", LanguageLibrary.GetCurrentLanguage()) + Environment.NewLine + Environment.NewLine);
					break;
			}

			body.Append(daoMaskText.GetText("TextUsername", LanguageLibrary.GetCurrentLanguage()) + ": '" + UserName + "'" + Environment.NewLine);
			body.Append(daoMaskText.GetText("TextPassword", LanguageLibrary.GetCurrentLanguage()) + ": '" + password + "'" + Environment.NewLine);
			mailItem.Body = body.ToString();
			mailItem.To = EmailAddress;
			mailItem.CC = ConfigurationManager.AppSettings["MailFrom"];

			mailItem.Display(false);
			try
			{
				mailItem.Send();
			}
			catch (Exception excep)
			{
				//[...]
			}
		}
	}
	catch (Exception ex)
	{
		//[...]
	}
}

30.01.2018 - 15:16 Uhr

Vielen Dank Sir Rufo!

Hast Recht, eine kleine foreach-Schleife über die Items mit einer zuvor gemerkten PKI wirkt wahre Wunder.
Nochmals Danke für den Tipp.

30.01.2018 - 13:55 Uhr

Hallo,

Wir arbeiten derzeit mit VS2015 an einer WPF-Applikation mit MVVM, die den DataGrid verwendet.

In den DataGrids haben wir unter Umständen die Möglichkeit, Daten zu filtern, was Einfluss auf die Items-Collection des DataGrid hat.
Nehmen wir an im ungefilterten Zustand enthält die Liste 100 Items, so sind es nach dem Filtern beispielsweise nur noch 20.

Wenn wir eine bestimmte Zeile im DataGrid doppelklicken, öffnet sich ein Edit-Dialog, in dem man Daten der betreffenden Zeile ändern und speichern kann.
Nach dem Schließen dieses Dialogs merken wir uns zuerst den aktuellen SelectedIndex des Grid, lesen die Daten neu in die Source ein (wodurch der SelectedIndex auf -1 gestellt wird) und setzen dann in SelectedIndex den gemerkten Index.

Wenn der DataGrid nicht gefiltert ist kann man den Index entweder auf zweierlei Art feststellen:

int currentIndex = grid.Items.IndexOf(grid.CurrentItem);

oder

int currentIndex = grid.SelectedIndex;

Wenn nun aber der Grid gefiltert ist, erhalten wir einen falschen Index.

Zum Beispiel:
Wir editieren im gefilterten Zustand die erste Zeile, die unter normalen Umständen die vierte in der Liste ist (Index = 3), aber wir bekommen Index = 0.
Wenn nun der Index 0 in einer Variable gemerkt wird und man nach dem Refresh der Source diesen wieder in SelectedIndex einstellt, wird nicht die erste Zeile in der gefilterten Liste selektiert, sondern die erste Zeile in der ungefilterten Gesamtliste.
Bei einem Blick auf das aktuelle SelectedItem zeigt sich sehr schnell, dass dieses das falsche ist.

Zwischenzeitlich habe ich noch den ItemContainerGenerator ausprobiert, aber leider auch hier ohne Erfolg:

var row = grid.ItemContainerGenerator.ContainerFromIndex(grid.SelectedIndex);
vm.RefreshList();
grid.SelectedIndex = grid.ItemContainerGenerator.IndexFromContainer(row);

In diesem Fall ist die Variable row nach dem Aufruf der Methode RefreshList Disconnected, also nicht mehr verfügbar.
Und selbst wenn ich vor dem Aufruf von RefreshList mit IndexFromContainter den Index von row hole erhalte ich den falschen Index - also auch hier 0 anstelle von 3.

Womit wir zur großen Frage kommen, wie kann ich den richtigen Index ermitteln - unabhängig davon, ob der DataGrid gefiltert ist oder nicht?

Vielen Dank im voraus.

30.01.2018 - 13:36 Uhr

Ich persönlich habe gute Erfahrungen mit CustomControls gemacht und gefallen mir auch besser wie UserControls.

11.11.2016 - 08:42 Uhr

Hallo MrSparkle,

Ich habe an der betreffenden Stelle in Controllers.cs folgendes ausprobiert:


$scope.selectedreason = "";
$scope.selectedreason = $scope.typeOfTestReasons[0];

Das bringt mir aber leider auch nichts.
Der Zustand ist immer noch derselbe wie vorher.
Wenn ich in dem ersten Select-Control das Item auswähle, über das das abhängige Select-Control sichtbar wird, steht im abhängigen Control noch immer das zuletzt ausgewählte Item.
8o

10.11.2016 - 09:40 Uhr

Ich arbeite derzeit mit Apache Cordova und Ionic an einer Web-Applikation.
Auf einer meiner Pages habe ich ein Select-Control (DropDownLists), das von der Auswahl in einem anderen Select-Control auf dieser Page abhängig ist.
In meinem Fall hängt die Sichtbarkeit des abhängigen Controls von einem bestimmten SelectedItem in dem ersten Select-Control ab.

Ich habe also folgenden Testfall:
Ich wähle in dem ersten Select-Control ein bestimmtes Item aus und das zweite Select-Control wird angezeigt.
Dann wähle ich in dem zweiten Control ein anderes Item als das erste aus.
Sobald ich ein anderes Item in dem ersten Control auswähle, verschwindet das abhängige Control und wird auf der Page nicht mehr angezeigt.
An dieser Stelle versuche ich im Code das SelectedItem des abhängigen Controls zurück zu setzen.
Soweit so gut.

Nun habe ich leider folgendesProblem:
Sobald ich im ersten Select-Control wieder das Item für die Anzeige des abhängigen Control auswähle, steht im abhängigen Control immer noch der zuletzt eingestellte Wert.

So sind meine Controls auf der Page definiert:


    <select id="ddl_type_of_test"
            ng-model="selectedtypeoftest"
            data-ng-options="typeOfTest as typeOfTest.name for typeOfTest in typeOfTests"
            ng-change="typeOfTestChanged(selectedtypeoftest)">
        <option value="{{typeOfTest.name}}"></option>
    </select>

    <select id="ddl_reason"
            ng-model="selectedreason"
            data-ng-options="typeOfTestReason as typeOfTestReason.name for typeOfTestReason in typeOfTestReasons"
            ng-change="typeOfTestReasonChanged(selectedreason)">
        <option value="{{typeOfTestReason.name}}"></option>
    </select>

Und dies ist der Code in controller.cs, der alles steuert:


.controller('TypeOfTestCtrl', function ($scope, TypeOfTests, TypeOfTestReasons, TypeOfTestUserReasons) {
    $scope.typeOfTests = TypeOfTests.all();
    $scope.typeOfTestReasons = TypeOfTestReasons.all();
    $scope.typeOfTestUserReasons = TypeOfTestUserReasons.all();

    $scope.typeOfTestChanged = function (item) {
        if (item.id == 'partial_acceptance_testing') {
            $scope.showTypeOfTestReason = true;
        }
        else {
            $scope.showTypeOfTestReason = false;
            $scope.showTypeOfTestUserReason = false;
            debugger;
            if (angular.isDefined($scope.typeOfTestReasons)) {
                delete $scope.typeOfTestReasons;
                $scope.typeOfTestReasons = TypeOfTestReasons.all();
                $scope.selectedreason = $scope.typeOfTestReasons[0].name;
            }
            if (angular.isDefined($scope.typeOfTestUserReasons)) {
                delete $scope.typeOfTestUserReasons;
                $scope.typeOfTestUserReasons = TypeOfTestUserReasons.all();
            }
        }
    };
    $scope.showTypeOfTestReason = false;
    $scope.showTypeOfTestUserReason = false;

    $scope.typeOfTestReasonChanged = function (item) {
        if (item.id == 'user_defined') {
            $scope.showTypeOfTestUserReason = true;
        }
        else {
            $scope.showTypeOfTestUserReason = false;
        }
    };
    $scope.showTypeOfTestUserReason = false;
})

Noch eine Anmerkung.
Wenn ich die Seite zur Laufzeit debugge, steht in $scope.selectedreason nach dem Setzen der korrekte Wert, aber wenn ich anschließend im ersten Select-Control wieder das Item auswähle, das für die Anzeige des abhängigen verantwortlich ist, steht in dem anhängigen immer noch der zuletzt eingestellte Wert.
Die Auswahl in dem anhängigen Select-Control wird nicht resettet.
Was muss ich noch hinzufügen, um den Reset auszuführen?

19.05.2016 - 09:01 Uhr

Okay, für das CustomControl, das von der TextBox erben tut, gibt es tatsächlich einen besseren Weg als Hardcoding.
Dazu muss man das Binding des Text-Property der inneren TextBox ändern:


<TextBox x:Name="innerTextBox"
    Text="{Binding Text, RelativeSource={RelativeSource TemplatedParent}, UpdateSourceTrigger=PropertyChanged}"
    [...]/>

18.05.2016 - 15:56 Uhr

Das Problem besteht darin, dass es im Generic.xaml innerhalb der CustomTextBox eine innere TextBox gibt, deren Text-Eigenschaft zwar die Einstellung der Text-Eigenschaft des CustomControls übernimmt, aber wenn man den Text der inneren TextBox ändert, dringt dies nicht zur CustomTextBox durch.
Hierzu muss man im Code des CustomControls ein wenig nachhelfen.

Zuerst müssen wir die innere TextBox finden und in einem Platzhalter merken.


        /// <summary>
        /// Gets or sets the inner textbox of this customcontrol.
        /// </summary>
        public TextBox InnerTextBox { get; set; }

        /// <summary>
        /// Overrides the method OnApplytemplate.
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            var innertextbox = this.GetTemplateChild("innertextbox");

            if (innertextbox != null && InnerTextBox == null)
            {
                InnerTextBox = innertextbox as TextBox;
                InnerTextBox.TextChanged -= InnerTextBoxTextChanged;
                InnerTextBox.TextChanged += InnerTextBoxTextChanged;
            }
        }

Und in dem EventHandler zum TextChanged-Event holen wir den Text der inneren TextBox und stellen ihn in den Text der CustomTextBox.


        /// <summary>
        /// The Text-property of the inner textbox was changed.
        /// So we have to change the Text-property of the CustomControl too -> update datasource.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The eventarguments.</param>
        private void InnerTextBoxTextChanged(object sender, TextChangedEventArgs e)
        {
            // sender = InnerTextBox
            string mytext = ((TextBox)sender).Text;
            this.Text = mytext;
        }

Zugegeben, es ist nicht gerade schön, aber es funktioniert.
Sollte jemand noch eine bessere Lösung haben, immer her damit!

18.05.2016 - 15:50 Uhr

Hallo witte,

Nicht wirklich. Lediglich in einem XAML habe ich mal die Controls eingefügt und die Text-Eigenschaft fix gesetzt.
Aber inzwischen habe ich in einem anderen Forum einen Hinweis gefunden, was schief gelaufen ist.
Mehr dazu in meiner selbst verfassten Antwort.

18.05.2016 - 14:18 Uhr

Ist mir klar, dass es ein sehr seltener Fall ist.
Leider muss ich es so machen, da wir an einem WPF-Tool arbeiten, mit dem man sich seine Masken selbst zusammenstellen kann.
Ist hie und da etwas tricky, aber bisher ging es eigentlich.
Nun ist halt das Problem mit dem Update der Datenquelle durch die CustomControls aufgetaucht.
Mit den normalen Controls ging es.
Also müsste es mit den CustomControls auch gehen, nur wie ist die spannende Frage.

18.05.2016 - 13:40 Uhr

Ich arbeite derzeit mit WPF und C# an einer WPF-Applikation, in der die Controls und ihre Bindings zur Laufzeit in Code-behind erzeugt werden.
Das WPF-Window auf dem ich die Controls erzeuge, hat ein ViewModel mit einer DataTable (die in DataContext eingestellt wird) und - am Fuss des WPF-Window - einen DataGrid, der an den DefaultView der DataTable gebunden ist.

Zuerst verwendete ich zum Erzeugen von Controls die normalen WPF-Controls, z.B. die TextBox und die CheckBox.
In deren Bindings setze ich UpdateSourceTrigger auf "PropertyChanged" wie hier:


    Binding controlBinding = new Binding();
    controlBinding.Source =

 ViewModelContainer.viewmodel.ApplicationDataSet.Tables[BindingSource].DefaultView;
    controlBinding.Path = new PropertyPath("[0][" + BindingPath + "]");
    controlBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;

Wenn ich nach der Generierung der Controls den Text der TextBox änderte (ohne sie zu verlassen) oder die Checkbox an-/abhakte, konnte ich die Änderungen im DataGrid augenblicklich sehen.

Nun aber verwende ich CustomControls die von den normalen WPF-Controls erben (um sie um neue Properties zu erweitern) und stelle leider fest, dass die UpdateSourceTrigger-Funktionalität nicht mehr arbeitet.
Wenn ich den Text der TextBox ändere oder die Checkbox an-/abhake, sehe ich keine Änderung im DataGrid und damit ist auch keine Änderung in der gebundenen DataTable vorhanden.

Wie man oben an meinem Codebeispiel sehen kann, tue ich bei meinen CustomControls Source bzw. DataContext auf die DataTable setzen.

Ich vermute, dass ich an den Definitionen der CustomControls im Generic.xaml etwas ändern muss, aber was?

Hier die Definitionen der CustomTextBox und der CustomCheckBox:


    <!--Style for the CustomControl CustomTextBox-->
    <Style TargetType="{x:Type local:CustomTextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:CustomTextBox}">
                    <Border BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <TextBox Text="{TemplateBinding Text}"
                                 TextWrapping="Wrap"
                                 HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                                 VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                                 ContextMenu="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:CustomTextBox}},
                            Path=ContextMenu}"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
    <!--Style for the CustomControl CustomCheckBox-->
    <Style TargetType="{x:Type local:CustomCheckBox}" BasedOn="{StaticResource {x:Type CheckBox}}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:CustomCheckBox}">
                    <Border BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <CheckBox IsChecked="{TemplateBinding IsChecked}"
                                  HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                                  VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">
                            <TextBlock Text="{TemplateBinding Text}"
                                       TextWrapping="Wrap"
                                       TextAlignment="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type CheckBox}},
                                Path=HorizontalContentAlignment, Converter={StaticResource h2tAlignmentConverter}}"
                                       TextDecorations="{TemplateBinding TextDecorations}"/>
                        </CheckBox>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Vielen Dank im voraus!

Patrick

27.04.2016 - 08:52 Uhr

In meinem Fall ist es leider so, dass der Kunde einen WPF-Designer haben möchte, wo er sich Steuerelemente aus einer Toolbox auf ein WPF-Window mit Canvas zieht.
Wenn ein Steuerelement auf dem Canvas abgelegt wurde, geht ein Einstellungsfenster auf, in dem man z.B. die Schrifteinstellungen manipulieren kann.
Später soll hier auch noch das DataBinding hinzukommen.
Wenn das WPF-Window fertig gestaltet ist, kann der Anwender es speichern und in der Applikation verwenden.
Für den Kunden geht es hauptsächlich darum, dass er seine Masken bei Bedarf um weitere Felder erweitern kann.
Darüberhinaus sollen die Metadaten mit den Steuerelementeigenschaften in einer DB abgespeichert werden.

Deswegen meine Nachfrage wegen dynamischer Generierung in code-behind.

26.04.2016 - 15:02 Uhr

Dass man bei normalen WPF-Anwendungen das Binding im XAML setzt, ist mir klar.
Nur habe ich es leider mit dynamisch generierten WPF-Fenstern zu tun, wobei ich die Steuerelemente und deren Bindings in Code-behind erstellen muss.

26.04.2016 - 14:02 Uhr

Ich bin nicht absolut sicher, aber ich glaube, ich habe es herausgefunden.
Man muss die Eigenschaft UpdateSourceTrigger des Binding-Objektes auf PropertyChanged stellen.
Zumindest in meiner kleinen Applikation läuft es nun, aber falls noch jemand andere Vorschläge hat, wäre ich dafür dankbar.


            // Nun erstellen wir das Binding für die TextBox.
            Binding controlbinding = new Binding();
            controlbinding.Source = viewmodel.ApplicationDataSet.Tables["table1"].DefaultView;
            controlbinding.Path = new PropertyPath("[0][Bezeichnung]");
            controlbinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            textbox.SetBinding(TextBox.TextProperty, controlbinding);

26.04.2016 - 13:51 Uhr

Hallo,

Ich arbeite mit VS 2015 an einer WPF-Applikation, bei der die Controls zur Laufzeit in Code-behind erstellt und an die Datenquelle gebunden werden.
Meine Datenquelle ist eine DataTable mit mehreren Spalten unterschiedlichen Datentyps (string, int, bool), die in einem DataSet abgelegt ist.

Auf meinem WPF-Fenster habe ich eine TextBox und eine Reihe von Checkboxen, die zur Laufzeit an bestimmte Spalten der DataTable gebunden werden.
Testweise lasse ich im Hintergrund einen Timer mitlaufen, so dass alle zehn Sekunden geprüft wird, ob Änderungen an meiner DataTable vorliegen.


        public string CheckdataForChanges(string tablename)
        {
            if (ApplicationDataSet.Tables[tablename].GetChanges() != null)
                return "Die Table wurde geändert";
            else
                return "Die Table wurde nicht geändert";
        }

Wenn ich die Einstellung einer Checkbox durch An- oder Abhaken ändere, wird dies sofort registriert und am Ende der Timerperiode kommt die entsprechende Meldung.
Ändere ich den Inhalt einer TextBox auf dem WPF-Fenster und verlasse die TextBox nicht (also kein LostFocus), wird keine Veränderung registriert.

Gibt es eine Möglichkeit die DataTable zu refreshen?
Da ich es mit einem dynamisch generierten Fenster zu tun habe, gibt es kein echtes ViewModel und damit auch nicht die Möglichkeit von INotifyPropertyChanged.

Vielen Dank im voraus,
Brendan

22.04.2016 - 10:05 Uhr

Okay, im Code des CustomControls habe ich zwar noch vergessen, die Teile des Templates zu definieren.
Dies nachzufügen hat mich leider auch nicht weiter gebracht.


    [TemplatePart(Name = "PART_Root", Type = typeof(Grid))]
    [TemplatePart(Name = "PART_Button", Type = typeof(Button))]
    [TemplatePart(Name = "PART_TextBox", Type = typeof(DatePickerTextBox))]

    public class MyDatePicker : DatePicker
        [...]

Keine Ahnung, was schief gelaufen ist.

22.04.2016 - 09:50 Uhr

Ich habe noch einen Versuch gemacht, indem ich ein CustomControl definierte und dieses in meine Toolbox implementierte.
Im Code des CustomControls "MyDatePicker" habe ich anschließend noch ein Property für die DatePickerTextBox hinzugefügt, das in OnApplyTemplate gesetzt werden sollte.
Leider wird auch hier die TextBox "PART_TextBox" nicht gefunden.
Was habe ich falsch gemacht?

Hier der Code des CustomControls:


    public class MyDatePicker : DatePicker
    {
        /// <summary>
        /// Gets the TextBox from the DatePicker.
        /// </summary>
        public DatePickerTextBox PartTextBox { get; private set; }

        static MyDatePicker()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(MyDatePicker), new FrameworkPropertyMetadata(typeof(MyDatePicker)));
        }

        /// <summary>
        /// Overrides the method OnApplyTemplate of the parent.
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            PartTextBox = this.GetTemplateChild("PART_TextBox") as DatePickerTextBox;
            var grid = this.GetTemplateChild("PART_Root");
            var button = this.GetTemplateChild("PART_Button");
            var datepickertextbox = this.GetTemplateChild("PART_TextBox");
        }
    }

Und meine Templatedefinition in Generic.xaml sieht so aus:


    <Style TargetType="{x:Type local:MyDatePicker}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:MyDatePicker}">
                    <Border BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Control.Padding}" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup Name="CommonStates" />
                        </VisualStateManager.VisualStateGroups>
                        <Grid Name="PART_Root" HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*" />
                                <ColumnDefinition Width="Auto" />
                            </Grid.ColumnDefinitions>
                            <Grid.Resources>
                                <ControlTemplate TargetType="Button" x:Key="e">
                                    <Grid>
                                        <VisualStateManager.VisualStateGroups>
                                            <VisualStateGroup Name="CommonStates" />
                                        </VisualStateManager.VisualStateGroups>
                                        <Grid Background="#11FFFFFF" Width="19" Height="18" FlowDirection="LeftToRight" Margin="0,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Center">
                                            <Grid.ColumnDefinitions>
                                                <ColumnDefinition Width="20*" />
                                                <ColumnDefinition Width="20*" />
                                                <ColumnDefinition Width="20*" />
                                                <ColumnDefinition Width="20*" />
                                            </Grid.ColumnDefinitions>
                                            <Grid.RowDefinitions>
                                                <RowDefinition Height="23*" />
                                                <RowDefinition Height="19*" />
                                                <RowDefinition Height="19*" />
                                                <RowDefinition Height="19*" />
                                            </Grid.RowDefinitions>
                                            <Border BorderThickness="1,1,1,1" CornerRadius="0,0,1,1" BorderBrush="#FF45D6FA" Name="Highlight" Margin="-1,-1,-1,-1" Opacity="0" Grid.Row="0" Grid.ColumnSpan="4" Grid.RowSpan="4" />
                                            <Border BorderThickness="1,1,1,1" CornerRadius="0.5,0.5,0.5,0.5" BorderBrush="#FFFFFFFF" Background="#FF1F3B53" Name="Background" Margin="0,-1,0,0" Opacity="1" Grid.Row="1" Grid.ColumnSpan="4" Grid.RowSpan="3" />
                                            <Border BorderThickness="1,1,1,1" CornerRadius="0.5,0.5,0.5,0.5" BorderBrush="#BF000000" Name="BackgroundGradient" Margin="0,-1,0,0" Opacity="1" Grid.Row="1" Grid.ColumnSpan="4" Grid.RowSpan="3">
                                                <Border.Background>
                                                    <LinearGradientBrush StartPoint="0.7,0" EndPoint="0.7,1">
                                                        <LinearGradientBrush.GradientStops>
                                                            <GradientStop Color="#FFFFFFFF" Offset="0" />
                                                            <GradientStop Color="#F9FFFFFF" Offset="0.375" />
                                                            <GradientStop Color="#E5FFFFFF" Offset="0.625" />
                                                            <GradientStop Color="#C6FFFFFF" Offset="1" />
                                                        </LinearGradientBrush.GradientStops>
                                                    </LinearGradientBrush>
                                                </Border.Background>
                                            </Border>
                                            <Rectangle StrokeThickness="1" Grid.ColumnSpan="4" Grid.RowSpan="1">
                                                <Rectangle.Fill>
                                                    <LinearGradientBrush StartPoint="0.46,1.6" EndPoint="0.3,-1.1">
                                                        <LinearGradientBrush.GradientStops>
                                                            <GradientStop Color="#FF4084BD" />
                                                            <GradientStop Color="#FFAFCFEA" Offset="1" />
                                                        </LinearGradientBrush.GradientStops>
                                                    </LinearGradientBrush>
                                                </Rectangle.Fill>
                                                <Rectangle.Stroke>
                                                    <LinearGradientBrush StartPoint="0.48,1.25" EndPoint="0.48,-1">
                                                        <LinearGradientBrush.GradientStops>
                                                            <GradientStop Color="#FF494949" />
                                                            <GradientStop Color="#FF9F9F9F" Offset="1" />
                                                        </LinearGradientBrush.GradientStops>
                                                    </LinearGradientBrush>
                                                </Rectangle.Stroke>
                                            </Rectangle>
                                            <Path Data="M11.426758,8.4305077L11.749023,8.4305077 11.749023,16.331387 10.674805,16.331387 10.674805,10.299648 9.0742188,11.298672 9.0742188,10.294277C9.4788408,10.090176 9.9094238,9.8090878 10.365967,9.4510155 10.82251,9.0929432 11.176106,8.7527733 11.426758,8.4305077z M14.65086,8.4305077L18.566387,8.4305077 18.566387,9.3435936 15.671368,9.3435936 15.671368,11.255703C15.936341,11.058764 16.27293,10.960293 16.681133,10.960293 17.411602,10.960293 17.969301,11.178717 18.354229,11.615566 18.739157,12.052416 18.931622,12.673672 18.931622,13.479336 18.931622,15.452317 18.052553,16.438808 16.294415,16.438808 15.560365,16.438808 14.951641,16.234707 14.468243,15.826504L14.881817,14.929531C15.368796,15.326992 15.837872,15.525723 16.289043,15.525723 17.298809,15.525723 17.803692,14.895514 17.803692,13.635098 17.803692,12.460618 17.305971,11.873379 16.310528,11.873379 15.83071,11.873379 15.399232,12.079271 15.016094,12.491055L14.65086,12.238613z" Stretch="Fill" Fill="#FF2F2F2F" Margin="4,3,4,3" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="4" Grid.RowSpan="3" />
                                            <Ellipse Fill="#FFFFFFFF" StrokeThickness="0" Width="3" Height="3" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.ColumnSpan="4" />
                                            <Border BorderThickness="1,1,1,1" CornerRadius="0,0,0.5,0.5" BorderBrush="#B2FFFFFF" Name="DisabledVisual" Opacity="0" Grid.Row="0" Grid.ColumnSpan="4" Grid.RowSpan="4" />
                                        </Grid>
                                    </Grid>
                                </ControlTemplate>
                                <SolidColorBrush x:Key="ee">#A5FFFFFF</SolidColorBrush>
                            </Grid.Resources>
                            <Button Foreground="{TemplateBinding TextElement.Foreground}" Name="PART_Button" Width="20" Margin="3,0,3,0" HorizontalAlignment="Left" VerticalAlignment="Top" Focusable="False" Grid.Column="1" Grid.Row="0">
                                <Button.Template>
                                    <ControlTemplate TargetType="Button">
                                        <Grid>
                                            <VisualStateManager.VisualStateGroups>
                                                <VisualStateGroup Name="CommonStates" />
                                            </VisualStateManager.VisualStateGroups>
                                            <Grid Background="#11FFFFFF" Width="19" Height="18" FlowDirection="LeftToRight" Margin="0,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Center">
                                                <Grid.ColumnDefinitions>
                                                    <ColumnDefinition Width="20*" />
                                                    <ColumnDefinition Width="20*" />
                                                    <ColumnDefinition Width="20*" />
                                                    <ColumnDefinition Width="20*" />
                                                </Grid.ColumnDefinitions>
                                                <Grid.RowDefinitions>
                                                    <RowDefinition Height="23*" />
                                                    <RowDefinition Height="19*" />
                                                    <RowDefinition Height="19*" />
                                                    <RowDefinition Height="19*" />
                                                </Grid.RowDefinitions>
                                                <Border BorderThickness="1,1,1,1" CornerRadius="0,0,1,1" BorderBrush="#FF45D6FA" Name="Highlight" Margin="-1,-1,-1,-1" Opacity="0" Grid.Row="0" Grid.ColumnSpan="4" Grid.RowSpan="4" />
                                                <Border BorderThickness="1,1,1,1" CornerRadius="0.5,0.5,0.5,0.5" BorderBrush="#FFFFFFFF" Background="#FF1F3B53" Name="Background" Margin="0,-1,0,0" Opacity="1" Grid.Row="1" Grid.ColumnSpan="4" Grid.RowSpan="3" />
                                                <Border BorderThickness="1,1,1,1" CornerRadius="0.5,0.5,0.5,0.5" BorderBrush="#BF000000" Name="BackgroundGradient" Margin="0,-1,0,0" Opacity="1" Grid.Row="1" Grid.ColumnSpan="4" Grid.RowSpan="3">
                                                    <Border.Background>
                                                        <LinearGradientBrush StartPoint="0.7,0" EndPoint="0.7,1">
                                                            <LinearGradientBrush.GradientStops>
                                                                <GradientStop Color="#FFFFFFFF" Offset="0" />
                                                                <GradientStop Color="#F9FFFFFF" Offset="0.375" />
                                                                <GradientStop Color="#E5FFFFFF" Offset="0.625" />
                                                                <GradientStop Color="#C6FFFFFF" Offset="1" />
                                                            </LinearGradientBrush.GradientStops>
                                                        </LinearGradientBrush>
                                                    </Border.Background>
                                                </Border>
                                                <Rectangle StrokeThickness="1" Grid.ColumnSpan="4" Grid.RowSpan="1">
                                                    <Rectangle.Fill>
                                                        <LinearGradientBrush StartPoint="0.46,1.6" EndPoint="0.3,-1.1">
                                                            <LinearGradientBrush.GradientStops>
                                                                <GradientStop Color="#FF4084BD" />
                                                                <GradientStop Color="#FFAFCFEA" Offset="1" />
                                                            </LinearGradientBrush.GradientStops>
                                                        </LinearGradientBrush>
                                                    </Rectangle.Fill>
                                                    <Rectangle.Stroke>
                                                        <LinearGradientBrush StartPoint="0.48,1.25" EndPoint="0.48,-1">
                                                            <LinearGradientBrush.GradientStops>
                                                                <GradientStop Color="#FF494949" />
                                                                <GradientStop Color="#FF9F9F9F" Offset="1" />
                                                            </LinearGradientBrush.GradientStops>
                                                        </LinearGradientBrush>
                                                    </Rectangle.Stroke>
                                                </Rectangle>
                                                <Path Data="M11.426758,8.4305077L11.749023,8.4305077 11.749023,16.331387 10.674805,16.331387 10.674805,10.299648 9.0742188,11.298672 9.0742188,10.294277C9.4788408,10.090176 9.9094238,9.8090878 10.365967,9.4510155 10.82251,9.0929432 11.176106,8.7527733 11.426758,8.4305077z M14.65086,8.4305077L18.566387,8.4305077 18.566387,9.3435936 15.671368,9.3435936 15.671368,11.255703C15.936341,11.058764 16.27293,10.960293 16.681133,10.960293 17.411602,10.960293 17.969301,11.178717 18.354229,11.615566 18.739157,12.052416 18.931622,12.673672 18.931622,13.479336 18.931622,15.452317 18.052553,16.438808 16.294415,16.438808 15.560365,16.438808 14.951641,16.234707 14.468243,15.826504L14.881817,14.929531C15.368796,15.326992 15.837872,15.525723 16.289043,15.525723 17.298809,15.525723 17.803692,14.895514 17.803692,13.635098 17.803692,12.460618 17.305971,11.873379 16.310528,11.873379 15.83071,11.873379 15.399232,12.079271 15.016094,12.491055L14.65086,12.238613z" Stretch="Fill" Fill="#FF2F2F2F" Margin="4,3,4,3" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="4" Grid.RowSpan="3" />
                                                <Ellipse Fill="#FFFFFFFF" StrokeThickness="0" Width="3" Height="3" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.ColumnSpan="4" />
                                                <Border BorderThickness="1,1,1,1" CornerRadius="0,0,0.5,0.5" BorderBrush="#B2FFFFFF" Name="DisabledVisual" Opacity="0" Grid.Row="0" Grid.ColumnSpan="4" Grid.RowSpan="4" />
                                            </Grid>
                                        </Grid>
                                    </ControlTemplate>
                                </Button.Template>
                            </Button>
                            <DatePickerTextBox HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Name="PART_TextBox" Focusable="{TemplateBinding UIElement.Focusable}" Grid.Column="0" Grid.Row="0" xml:space="preserve" /><Grid Name="PART_DisabledVisual" Opacity="0" IsHitTestVisible="False" Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2"><Grid.ColumnDefinitions><ColumnDefinition Width="*" /><ColumnDefinition Width="Auto" /></Grid.ColumnDefinitions><Rectangle RadiusX="1" RadiusY="1" Fill="#A5FFFFFF" Grid.Column="0" Grid.Row="0" /><Rectangle RadiusX="1" RadiusY="1" Fill="#A5FFFFFF" Width="19" Height="18" Margin="3,0,3,0" Grid.Column="1" Grid.Row="0" /><Popup Placement="Bottom" StaysOpen="False" AllowsTransparency="True" Name="PART_Popup" /></Grid></Grid>
                    </Border>
                    <ControlTemplate.Triggers>
                        <DataTrigger Binding="{Binding Path=(SystemParameters.HighContrast)}" Value="false">
                            <Setter Property="TextElement.Foreground" TargetName="PART_TextBox">
                                <Setter.Value>
                                    <Binding Path="Foreground" RelativeSource="{RelativeSource Mode=TemplatedParent}" />
                                </Setter.Value>
                            </Setter>
                        </DataTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

20.04.2016 - 15:25 Uhr

Ich arbeite derzeit an einem WPF-Windowdesigner mit VS 2015.
Ich habe ein Toolbox-Window, von dem ich mit Drag-and-Drop Controls zu meinem Entwurfsfenster ziehen kann.
Jedes Mal, wenn ich ein Control auf dem Entwurfsfenster fallen lasse, erstelle ich im Code für das Control/Frameworkelement ein Kontextmenü und überschreibe somit das Standardmenü (sofern es vorhanden ist) wie hier:


    private void ElementAddContextMenu(FrameworkElement element)
    {
        ContextMenu menu = new ContextMenu();
        MenuItem menuitem = new MenuItem();
        menuitem.Header = "Edit";
        menuitem.DataContext = element;
        menuitem.Click += EditElementProperties;
        menu.Items.Add(menuitem);

        element.ContextMenu = menu;
    }

Wie Ihr sehen könnt, binde ich das Click-Ereignis des Menuitem "Edit" an den Eventhandler EditElementProperties und setze das übergebene Frameworkelement in das DataContext-Property, weil ich das Element in EditElementProperties noch verwenden will.


    private void EditElementProperties(object sender, RoutedEventArgs e)
    {
        var element = ((MenuItem)sender).DataContext;
        changeTextWindow.changeTextOfElement((FrameworkElement)element);
    }

Das Kontextmenü funktioniert bei fast allen Controls sehr gut - sogar bei der TextBox - aber mit dem DatePicker will es nur zur Hälfte klappen.
Dieses Control scheint ein etwas sonderbar zu sein.

Wenn ich irgendwo auf dem DatePicker - außerhalb der TextBox klicke (die das Datum enthält) funktioniert es und mein Kontextmenü öffnet sich.
Aber für den Fall, dass ich auf die TextBox des DatePicker klicke, öffnet sich das Standardmenü (Ausschneiden, Kopieren, Einfügen).

Kann man auch dieses Kontextmenü im Code-behind überschreiben?

Ich weiß, dass es einen Weg durch das Definieren eines Stils für TextBox im DatePicker gibt, aber wir wollen das im XAML unserer Toolbox nicht verwenden, da wir befürchten, dass es beim Drag-and-Drop zu unvorhersehbaren Effekten führen könnte.
Daher möchten wir das Kontextmenü erst nach dem Drop im Entwurfsfenster hinzufügen.

Ist dies möglich?

Herzliche Grüße,
Brendan

P.S.:
Es scheint einen Weg über das Template des DatePickers zu geben, aber irgendwie komme ich hier auch nicht recht weiter, da meine Variable datepickertextbox immer null ist.


        private void ElementAddContextMenu(FrameworkElement element)
        {
            ContextMenu menu = new ContextMenu();
            MenuItem menuitem = new MenuItem();
            menuitem.Header = "Edit";
            menuitem.DataContext = element;
            menuitem.Click += EditElementProperties;
            menu.Items.Add(menuitem);

            element.ContextMenu = menu;

            if (element.GetType() == typeof(DatePicker) && element.GetType().GetProperty("Template") != null)
            {
                var template = (ControlTemplate)element.GetType().GetProperty("Template").GetValue(element);
                DatePicker datepicker = (DatePicker)element;
                DatePickerTextBox datepickertextbox = template.FindName("PART_TextBox", datepicker) as DatePickerTextBox;
                if (datepickertextbox != null)
                {
                    datepickertextbox.ContextMenu = menu;
                }
            }
        }

15.04.2016 - 12:07 Uhr

Noch mal hallo!

Ich habe es inzwischen herausgefunden.
Das Problem besteht darin, dass die Source-Eigenschaft des Image nicht auf Content referenzieren kann, da das Image bereits der Content ist.

Stattdessen muss Source mit Content.Source verbunden werden.
Dann klappt's.


<Image x:Name="displayimage"
            Grid.Row="1"
            HorizontalAlignment="Stretch"
            Source="{Binding Content.Source, RelativeSource={RelativeSource TemplatedParent}}"
            Margin="5,2,5,2"/>

15.04.2016 - 12:01 Uhr

Hallo,

Ich arbeite zur Zeit mit VS 2015 an einem WPF-Projekt.
Vor Kurzem habe ich für den ToggleButton in App.xaml ein Style-Template definiert, damit die Anwender - auch für den Fall, dass einer der Buttons den Fokus hat - sehen können, wie der IsChecked-Status des Buttons ist.
Ursprünglich war der Content des Buttons ein TextBlock, dessen Text ich in meinen WPF-Windows dann durch die Content-Eigenschaft setzen konnte.

Nun wollte ich diesen TextBlock durch ein Image ersetzen und dessen Source-Eigenschaft an Content binden.
Daneben habe ich in App.xaml ein paar Resourcen für die Images eingefügt.

Meine Ressourcen habe ich folgendermaßen definiert:


    <Application.Resources>
        <!-- Style for togglebuttons-->
        <Style x:Key="toggleButtonStyle" TargetType="{x:Type ToggleButton}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Border x:Name="outer"
                                BorderBrush="Black"
                                BorderThickness="1"
                                Margin="5,5,0,0"
                                Opacity=".9"
                                Background="Transparent">
                            <Border x:Name="inner"
                                      Margin="5"
                                      BorderThickness="0"
                                      Background="{Binding Background, RelativeSource={RelativeSource TemplatedParent}}">
                                <Grid x:Name="container">
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="2*"/>
                                        <RowDefinition/>
                                    </Grid.RowDefinitions>
                                    <!--<TextBlock x:Name="display"
                                               Grid.Row="1"
                                               TextAlignment="Center"
                                               Text="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}"
                                               Margin="5,2,5,2"/>-->
                                    <Image x:Name="displayimage"
                                           Grid.Row="1"
                                           HorizontalAlignment="Stretch"
                                           Source="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}"
                                           Margin="5,2,5,2"/>
                                </Grid>
                            </Border>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="ToggleButton.IsChecked" Value="True">
                                <Setter TargetName="outer" Property="Background" Value="LightBlue"/>
                                <Setter TargetName="outer" Property="BorderBrush" Value="Transparent"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <Image x:Key="imageHorizontalAlignmentLeft" Source="C:/Utilities/VS 2015 ImageLibrary/2015_VSIcon/AlignLeft/AlignLeft_16x.png"/>
        <Image x:Key="imageHorizontalAlignmentCenter" Source="C:/Utilities/VS 2015 ImageLibrary/2015_VSIcon/AlignStretchHorizontal/AlignStretchHorizontal_16x.png"/>
        <Image x:Key="imageHorizontalAlignmentRight" Source="C:/Utilities/VS 2015 ImageLibrary/2015_VSIcon/AlignRight/AlignRight_16x.png"/>
    </Application.Resources>

Und in meinen ToogleButtons versuchte ich den Content folgendermaßen zu setzen:


<ToggleButton x:Name="setAlignLeft" Grid.Row="1" Grid.Column="1" Content="{StaticResource imageHorizontalAlignmentLeft}"  Style="{StaticResource toggleButtonStyle}" Click="setAlignLeft_Click"/>

Leider führt dies nicht zum gewünschten Ergebnis.
Der Content des ToogleButtons bleibt leer und das Bild wird nicht angezeigt.
Daraufhin habe ich dasselbe mit einem ToogleButton versucht, der den Style toggleButtonStyle nicht verwendet.
Hier wird das Bild angezeigt, daher vermute ich mal, dass es wohl an dem Image im Template liegt, aber ich weiß nicht, wo ich ansetzen muss.

Weiß jemand Rat?

Vielen dank im voraus!
Brendan

15.04.2016 - 09:28 Uhr

Über Deinen Artikel bin ich bereits letzte Woche gestolpert und ich fand ihn sehr interessant.
Leider haben wir uns in unserer Gruppe für einen anderen Weg betreffend Move-and-Resize entschieden, was das Leben nicht gerade leichter macht.
Trotzdem vielen Dank!

14.04.2016 - 10:29 Uhr

Hallo,

Ich mache zur Zeit mit VS 2015 und WPF einen WPF-Maskendesigner, wobei man aus einer Art Toolbox bestimmte Steuerelemente auf ein WPF-Window mit einem Canvas ziehen, verschieben und resizen kann.

Dabei bin ich beim Verschieben von WPF-Controls, die bereits auf das Window gezogen worden sind, auf das Problem gestoßen, dass man beim MouseDown-Event - abhängig davon, ob das betreffende Control wie z.B. die TextBox eine EditBox hat - den Startpunkt für Drag&Drop unterschiedlich ermitteln muss.

Fall TextBox:

Point startpoint = e.GetPosition(null);

Sonstige (z.B. Label, TextBlock):

Point startpoint = e.GetPosition(parent);

Das parent-Control ist - wie gesagt - in meinem Fall ein Canvas Panel.
Die zweite Version mit dem parent brauche ich, weil es ansonsten beim Resizen von Controls wie z.B. dem Label Probleme gibt (Wenn man von links unten oder rechts unten resizen möchte).

Um Exceptions beim Verschieben von TextBoxen und DatePickern vorzubeugen habe ich einen provisorischen Workaround programmiert:

public void frameworkElementDragDropMouseDown(object sender, MouseButtonEventArgs e)
{
    if (sender.GetType() == typeof(TextBox) || sender.GetType() == typeof(DatePicker))
        startPoint = e.GetPosition(null);
    else
        startPoint = e.GetPosition(canvaspanel);
}

Gibt es irgendeine andere Möglichkeit zu prüfen, ob ein Control eine EditBox besitzt, damit die Prüfung ganz allgemein für solche Controls funktioniert?

Vielen Dank im voraus!
Brendan

11.04.2016 - 12:47 Uhr

Hallo,

Ich entwickle mit VS 2015 und WPF einen Maskendesigner, in dem man per Drag&Drop neue Controls einfügen, verschieben und resizen kann.
Eines dieser Controls ist ein Label, dessen Content wiederum ein TextBlock ist.

In XAML sieht das folgendermaßen aus:

    <Label Background="AliceBlue" HorizontalAlignment="Left" Margin="10,5,0,0" VerticalAlignment="Top">
        <TextBlock TextWrapping="Wrap" Height="Auto">Label</TextBlock>
    </Label>

Beim TextBlock habe ich TextWrapping auf "Wrap" und Height auf "Auto" gestellt.
Wenn ich nun versuche, die Höhe des Labels bis zu seinem erlaubten Minimum zu reduzieren, sollte der Content des TextBlock noch immer vollständig angezeigt werden.
Testweise habe ich dies mit einem reinen TextBlock ausprobiert und da hat es dank Height="Auto" funktioniert.

Wenn ich es nun aber mit einem Label versuche, das einen TextBlock als Content hat, wird beim Minimieren der Höhe der Content des TextBlock nicht mehr vollständig angezeigt.

Gibt es in XAML eine Möglichkeit, Eigenschaften des Parent mit denen von Children zu synchronisieren?
Dass der umgekehrte Weg geht (Children zu Parent) weiss ich.

Vielen Dank im voraus!

31.03.2016 - 15:45 Uhr

Danke, den Artikel habe ich heute Morgen bei meinen Nachforschungen ebenfalls entdeckt.
Einziges Problem:
Wenn man bei dem Binding für die TextBox Elementname anstelle von Source setzt, wird das Binding korrekt serialisiert.
Tut man jedoch - was bei generisch erzeugten Controls in diesem Fall zwingend notwendig ist - der Source-Eigenschaft den Datagrid zuweisen, steht nach der Serialisierung im Binding nur der Path und die Source fehlt.

30.03.2016 - 17:17 Uhr

Wir versuchen derzeit mit VS 2013 und WPF einen WPF-Window-Designer zu programmieren.
In dieser App werden controls zur laufzeit erstellt und auf einem Canvas abgelegt.
Darüberhinaus werden die Eigenschaften und Bindings im Code eingestellt.
Zu guter Letzt wollen wir das Canvas und die darauf befindlichen Controls serialisieren, wofür wir den XamlWriter verwenden:

    public string SerializeControlToXaml(FrameworkElement control)
    {
        StringBuilder outstr = new StringBuilder();
    
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.Indent = true;
        settings.OmitXmlDeclaration = true;
        XamlDesignerSerializationManager dsm =
            new XamlDesignerSerializationManager(XmlWriter.Create(outstr, settings));
        dsm.XamlWriterMode = XamlWriterMode.Expression;
        System.Windows.Markup.XamlWriter.Save(control, dsm);
    
        string xaml = outstr.ToString();
        return xaml;
    }

Der "control" Parameter beinhaltet das Canvas und ist der Parent für alle code-behind erstellten Controls.
Unter anderem erstellen wir TextBoxen, die an SelectedItem und eine Column von einem DataGrid gebunden sind.

 private void CreateTextboxes()
    {
        CreateTextbox("firstname", _datagridname, "SelectedItem.vorname", 220, 10);
        CreateTextbox("familyname", _datagridname, "SelectedItem.nachname", 220, 40);
    }

    private void CreateTextbox(string name, string sourceName, string path, double leftPos, double topPos)
    {
        TextBox tb = new TextBox();
        tb.SetValue(Canvas.LeftProperty, leftPos);
        tb.SetValue(Canvas.TopProperty, topPos);
        tb.Width = 150;
        tb.Name = name;
    
        // Binding to the selected item of the DataGrid.
        Binding tbbinding = new Binding();
        FrameworkElement sourceElement;
        ControlList.TryGetValue(sourceName, out sourceElement);
        if (sourceElement != null)
        {
            tbbinding.Source = sourceElement;
        }
        tbbinding.Path = new PropertyPath(path);
        tb.SetBinding(TextBox.TextProperty, tbbinding);
    
        _canvasPanel.Children.Add(tb);
    
        // The new TextBox is added to the Controllist.
        ControlList.Add(name, tb);
    }

Am Ende haben wir zwei TextBoxen, die an die DataGrid-Columns "firstname" und "familyname" gebunden sind.
Der Parameter "sourceName" enthält den Namen des DataGrid-Controls.
Wenn man mit zur Laufzeit generierten Controls arbeitet, muss man beim Binding einer TextBox anstelle von ElementName die Source-Eigenschaft setzen.
Diese bekommt - wie man im Code sieht - den DataGrid.

Wenn wir nun das Parent/Canvas serialisieren, fehlen die Bindings:

    <Canvas Background="#FFF0F8FF" Name="DropInCanvas" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:sd="clr-namespace:System.Data;assembly=System.Data" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
      <DataGrid CanUserAddRows="False" AutoGenerateColumns="True" Name="datagrid1" Canvas.Left="20" Canvas.Top="10">
        <DataGrid.ItemBindingGroup>
          <BindingGroup Name="{x:Null}" NotifyOnValidationError="False" ValidatesOnNotifyDataError="True" SharesProposedValues="True" />
        </DataGrid.ItemBindingGroup>
        <sd:DataRowView />
        <sd:DataRowView />
        <sd:DataRowView />
        <sd:DataRowView />
      </DataGrid>
      <TextBox Name="firstname" Width="150" Canvas.Left="220" Canvas.Top="10" xml:space="preserve"></TextBox>
      <TextBox Name="familyname" Width="150" Canvas.Left="220" Canvas.Top="40" xml:space="preserve"></TextBox>
    </Canvas>

Weiß jemand warum das so ist und was man eventuell dagegen tun kann?

Danke im voraus!

Brendan


24.02.2015 - 11:42 Uhr

Hallo,

Wir möchten für unsere WPF-Applikation automatisierte Tests mit VS 2012 Coded UI Test aufnehmen.
Auf der Maske liegt unter anderem eine ListBox mit diversen ListBoxItems für die Menüpunkte.
Alle Controls sind mit AutomationIDs versehen.
Wenn ich während der Aufnahme auf einen dieser Menüpunkte klicke, würde ich in der anschließend generierten UI Control Map (UI-Steuerelementezuordnung) folgenden Baum erwarten:

WPF-Window

  • TabControl
    • TabItem
      • Expander
        • ListBox
          • ListBoxItem

Tatsächlich aber erhalte ich die folgende Hierarchie:

WPF-Window

  • Expander
    • ListBox
      • ListBoxItem

Aus irgendeinem ominösen Grund werden das TabControl und das TabItem, auf dem die übrigen Controls liegen unterschlagen.

Zu Testzwecken habe ich ein kleines WPF-Programm mit einem kürzeren und überschaubareren XAML angelegt.


<Window x:Class="PseudoStaffDirector.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="400" Width="700">
    <Grid Name="MainGrid"
          AutomationProperties.AutomationId="mainGridID">
        <TabControl Name="PmTabControl"
                    AutomationProperties.AutomationId="pmTabControlID">
            <TabItem Name="Workspace"
                     AutomationProperties.AutomationId="tabItemStartseiteID"
                     Header="Startseite">
                <Grid Name="WorkspaceGrid"
                      AutomationProperties.AutomationId="workspaceGridID">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="200" />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    
                    <Expander Name="RadExpander"
                              Grid.Column="0"
                              Grid.Row="0"
                              ExpandDirection="Right"
                              AutomationProperties.AutomationId="radExpanderID">
                        <ListBox Name="HaptMenu"
                                 AutomationProperties.AutomationId="haptMenuID">
                            <ListBoxItem Name="PersonListBoxItem"
                                         Content="Person"
                                         FontSize="16"
                                         AutomationProperties.AutomationId="personListBoxItemID" />
                            <ListBoxItem Name="VerwaltungListBoxItem"
                                         Content="Verwaltung"
                                         FontSize="16"
                                         AutomationProperties.AutomationId="verwaltungListBoxItemID" />
                        </ListBox>
                    </Expander>
                </Grid>
            </TabItem>
        </TabControl>
    </Grid>
</Window>

Mit diesem WPF habe ich einen Test mit zwei Aktionen aufgenommen.
Bei der ersten Aktion handelt es sich um einen einfachen Mausklick auf eines der beiden ListBoxItems.
Die zweite Aktion ist ein Doppelklick auf eines der ListBoxItems.
Wenn ich anschließend einen Blick in die UI-Steuerelementzuordnung werfe, sehe ich folgendes Resultat:
Aktion 1: Bei einfachem Mausklick stimmt die Zuordnung.
Aktion 2: Bei Doppelklick fehlen wieder das TabControl und das TabItem.

Kann mir jemand sagen, wie diese falsche Zuordnung zustande kommt und man dies vermeiden kann?

Vielen Dank im voraus!

21.06.2013 - 10:00 Uhr

Guten Tag,

Wir verwenden in unserer Anwendung den TrueDBGrid von ComponentOne.
In den Columns gibt es ein Property namens NumberFormat, in dem man Format-Strings hinterlegen kann.
Bisher haben wir bei Zahlen über den entsprechenden Format-String die Darstellung von Nullwerten - also z.B. 0,00 - unterdrückt.
Nun ist bei uns die Frage aufgetaucht, ob man dasselbe für DateTime-Felder machen könnte, die in den Daten z.B. "01.01.0001" enthalten.
Bisher ist für Datumsfelder als NumberFormat "d" für ShortDate eingestellt.

Weiß jemand Rat?

Mit freundlichen Grüßen und schönes Wochenende,
Brendan

14.09.2012 - 14:04 Uhr

Hallo,

Ich möchte mein Problem noch mal kurz erklären.
In einer Methode M wird eine asynchrone Methode M1 gerufen, die ihrerseits eine weitere asynchrone Methode aufrufen tut.
Diese Methode soll einen asynchronen Datenbankzugriff ausführen.
Sie ist zwar als async Task definiert, allerdings wird der erforderliche Await hier durch die Anweisung "await Run.Task" abgedeckt.
Ich konnte nun feststellen, dass dieser Task.Run tatsächlich für mein Problem verantwortlich ist, da hiernach (bevor der restliche Code in Methode M1 abgearbeitet ist) man sich wieder in Methode M befindet.

Einen der Problemfälle konnte ich nun dadurch lösen, indem ich die asynchrone Datenbankabfrage in eine eigene Methode verlagert habe.
Außerdem habe ich Task.Run durch eine Action ersetzt.
Das sieht dann so aus:

private asnyc Task<bool> DoAsyncDatabaseQuery(...)
{
    await Task.Delay(0);
    Action f = async () =>
    {
        await Task.Delay(0);
        command.ExecuteNonQuery();
    };
    f();
    return true;
}

Eine Frage bleibt noch.
Wie kann man eine Action - ähnlich dem obigen Beispiel - definieren, die beispielsweise ein DataSet zurückgibt?

13.09.2012 - 08:30 Uhr

Hallo erst mal!

Wir sind zur Zeit dabei unsere Software auf asynchron umzustellen und haben nun ein Problem mit Methoden, die ursprünglich nacheinander und nun durcheinander laufen.
Das Merkwürdige daran ist, dass dies immer bei Datenbankoperationen geschieht.

Hier ein Beispiel:
Wir haben zwei Methodenaufrufe, die bisher sauber nacheinander abgewickelt wurden.

await Method1Async;
await Method2Async;

Nun ist es so, dass mitten im Code von Method1Async eine Datenbankabfrage steckt, die so ausgeführt wird:

await Task.Run(() =>
{
    command.ExecuteNonQuery();
});

Die Methode, in der der obige Execute-Befehl sich befindet, ist als async Task definiert.
Nachdem der Execute ausgeführt wurde, springt der Debugger zu der Stelle mit den Methodenaufrufen und führt dann Method2Async so lange aus, bis diese beendet ist oder - was die Sache richtig rund macht - hier ebenfalls eine Datenbankoperation - ähnlich der obigen - ausgeführt wird.
Dann geht es wieder zurück zu Method1Async, wo dann deren Code weiter ausgeführt wird.

Meine Frage ist nun, wie wir dieses Hinundherhüpfen zwischen den asynchronen Methoden vermeiden können.
Ich persönlich vermute, dass es an Task.Run liegt, zumal diese Anweisung normalerweise einen neuen Task startet.

Für Vorschläge und Anregungen wäre ich sehr dankbar.

05.06.2012 - 15:05 Uhr

Hallo !

Wir haben zu ComboBoxen auf unseren Masken ein Kontextmenü hinzugefügt, das unter anderem den Punkt "Rückgängig" enthält.
Sinn dieses Menüpunktes ist es, nachdem der Anwender aus der Itemliste einen anderen Eintrag ausgewählt hat, den vorhergehenden wieder herstellen zu können.
Wir hatten angenommen, dass dies so geht:

SendMessage(mComboBox.Handle, WM_UNDO, 0, 0);

Leider tut sich bei Ausführung dieser Anweisung gar nichts.
Ebenso wenig bei dieser Fassung:

[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
SendMessage(FindWindowEx(mComboBox.Handle,IntPtr.Zero,string.Empty,string.Empty), WM_UNDO, 0, 0);

Weiss jemand Rat?

Mit freundlichen Grüßen,
Brendan

16.11.2007 - 13:58 Uhr

Hallo Robert,

Du hast es zwar nicht genauer erwähnt, aber ich gehe mal davon aus, daß sich in Deinem DataSet eine Reihe von DataTables verbirgt.
HasChanges kann bei diesen mit der Methode AcceptChanges "neutralisiert" werden.

Tschau

31.10.2007 - 13:48 Uhr

verwendetes Datenbanksystem: <IBM i5>

Hallo alle miteinander!

Ich würde gerne wissen, wie man in einen OLEDB-ConnectionString eine Liste mit verschiedenen Datenbankbibliotheken integrieren kann.
Bei uns ist es so, daß die einzelnen Dateien über ein halbes Dutzend Bibliotheken verstreut sind und man nicht genau weiss, was eigentlich wo ist.

Vielen Dank im voraus für jeden Tip!

01.12.2006 - 10:09 Uhr

Hallo thomassa,

Entschuldige, ich habe gerade erst gemerkt, daß Du noch mit VS2003 programmierst.
Mein erster Lösungvorschlag war mit VS2005 gemacht - da sieht man wie Microsoft ständig alles ändern tut.
In VS2003 geht das nähmlich ganz anders und etwas komplizierter.

		private void Form1_Load(object sender, System.EventArgs e)
		{
			DataTable dt = new DataTable();
			DataSet ds = new DataSet();
			String constTableName = "Namensliste";

            dt.Columns.Add("col1",typeof(String));
			dt.Rows.Add(dt.NewRow());
			dt.TableName = constTableName;
			ds.Tables.Add(dt);
			this.dataGrid1.SetDataBinding(ds,constTableName);

			DataGridTableStyle dgts = new DataGridTableStyle();
			dgts.MappingName="Namensliste";
			//DataGridBoolColumn dc = new DataGridBoolColumn();
			DataGridTextBoxColumn dc = new DataGridTextBoxColumn();
			dc.MappingName="col1";
			dc.HeaderText="Name";
			dgts.GridColumnStyles.Add(dc);
			this.dataGrid1.TableStyles.Add(dgts);
		}

Zuerst erstelle ich eine leere DataTable mit einer einzigen Spalte namens col1.
Die DataTable bekommt den Namen "Namensliste" und wird in ein DataSet gestellt.
Dann muss - um die Texte der Spaltenköpfe anzupassen - ein DataGridTableStyle erstellt werden.
Dieser bekommt denselben Namen wie die DataTable.
Daraufhin müssen dem DataGridTableStyle nochmals alle Columns aus der DataTable als DataGridTextBoxColumn hinzugefügt werden.
Der MappingName ist der normale Name der Column und HeaderText die Spaltenkopfbeschriftung.
Zu guter Letzt wird der TableStyle dem DataGrid beigefügt.
Wenn man dieses kleine Beispiel nun laufen lässt, sieht man am Ende einen DataGrid mit einer Spalte, die mit "Name" beschriftet ist.

Damit hätten wir es nun also endlich.
Ach ja - eine Kleinigkeit noch. Man kann auch DataColumns mit Auswahlkästchen generieren.
Dazu muss anstelle von DataGridTextBoxColumn aber DataGridBoolColumn verwendet werden und ich schätze, daß die Spalte in der DataTable wahrscheinlich vom Typ Boolean sein muss.

Ich hoffe, daß ich Dir dieses Mal wirklich helfen konnte und Dich nicht allzusehr verwirrt habe.

Tschau!

29.11.2006 - 09:44 Uhr

Hallo Thomassa,

Hier mal ein kleines Beispiel für den Umgang mit dem DataGrid - ich hoffe, es nützt Dir.

            DataSet ds = new DataSet();
            DataTable dt = new DataTable();
            dt.Columns.Add("colVorname", typeof(String));
            dt.Columns.Add("colNachname", typeof(String));
            dt.Rows.Add(dt.NewRow());
            dt.Rows[0]["colVorname"] = "Hans";
            dt.Rows[0]["colNachname"] = "Dampf";
            dt.TableName = "Personen";
            ds.Tables.Add(dt);

            this.dataGridView1.DataSource = ds.Tables["Personen"];

Hier wird zuerst die Struktur einer DataTable erstellt.
Dann füge ich eine neue DataRow hinzu und fülle diese mit Daten.
Die DataTable wird anschliessend in ein DataSet übertragen.
Die DataSource des Grid wird dann an die DataTable gebunden, die sich im DataSet befindet.
Wenn man dies so macht, sieht man in den Spaltenköpfen die Namen der Columns aus der DataTable; also "colVorname" und "colNachname".

Die Beschriftung der Spaltenköpfe wird folgendermaßen angepasst:

            this.dataGridView1.Columns["colVorname"].HeaderText = "Vorname";
            this.dataGridView1.Columns["colNachname"].HeaderText = "Nachname";

Nun sollte in den Spaltenköpfen "Vorname" bzw. "Nachname" stehen.

Ich hoffe, daß ich Dir damit etwas weiterhelfen konnte.
8)

28.11.2006 - 15:13 Uhr

Vielen Dank Leute !!!

Muss mich erst noch daran gewöhnen, daß CSharp keine echte Unterscheidung zwischen Routinen und Funktionen macht, wie in anderen Programmiersprachen.
An "Return" - so wie ich es schon aus Funktionen in VB kenne - hätte ich in diesem Fall gar nicht gedacht.

Also, nochmals vielen Dank für Eure reichhaltigen Antworten.

28.11.2006 - 12:10 Uhr

Hallo alle miteinander!

Ich habe vor 3 Wochen begonnen mit CSharp zu programmieren.
Vorher habe ich sehr viel mit Visual Basic gemacht.
Dort gab es die Möglichkeit - innerhalb einer IF-Abfrage - die Methode mit "Exit Sub/Function" zu verlassen.
Gibt es in CSharp hierzu ein Äquivalent?

Ich meine wohlgemerkt nich Break!
Dieser Befehl funktionert ja nur bei Switch und Schleifen mit Loop oder For.

Vielen Dank im voraus!
8)